From 6aa477e0ccb1d2eb53f8e9ad72af3fa7b09d9619 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Wed, 13 Mar 2013 01:52:36 +0900 Subject: [PATCH] Tizen 2.1 base --- AUTHORS | 38 +- COPYING | 43 +- ChangeLog | 999 +- INSTALL | 244 +- Makefile.am | 276 +- NEWS | 326 + README | 98 + autogen.sh | 28 +- configure.ac | 2271 +++ debian/changelog | 1346 ++ debian/compat | 2 +- debian/control | 217 +- debian/copyright | 26 +- debian/jobs | 0 debian/libecore-bin.install | 2 +- debian/libecore-con-svn-01.install | 1 + debian/libecore-con-svn-01.shlibs | 1 + debian/libecore-con.install | 1 + debian/libecore-config-svn-01.install | 1 + debian/libecore-config-svn-01.shlibs | 1 + debian/libecore-config.install | 1 + debian/libecore-dev.install | 14 +- debian/libecore-doc.doc-base | 10 + debian/libecore-evas-svn-01.install | 1 + debian/libecore-evas-svn-01.shlibs | 1 + debian/libecore-evas.install | 1 + debian/libecore-fb-svn-01.install | 1 + debian/libecore-fb-svn-01.shlibs | 1 + debian/libecore-fb.install | 1 + debian/libecore-file-svn-01.install | 1 + debian/libecore-file-svn-01.shlibs | 1 + debian/libecore-file.install | 1 + debian/libecore-imf-svn-01.install | 2 + debian/libecore-imf-svn-01.shlibs | 2 + debian/libecore-imf.install | 2 + debian/libecore-input-svn-01.install | 1 + debian/libecore-input-svn-01.shlibs | 1 + debian/libecore-input.install | 1 + debian/libecore-ipc-svn-01.install | 1 + debian/libecore-ipc-svn-01.shlibs | 1 + debian/libecore-ipc.install | 1 + debian/libecore-svn-01.install | 1 + debian/libecore-svn-01.shlibs | 1 + debian/libecore-x-svn-01.install | 1 + debian/libecore-x-svn-01.shlibs | 1 + debian/libecore-x.install | 1 + debian/libecore.install | 1 + debian/rules | 51 +- doc/Doxyfile.in | 221 + doc/Makefile.am | 33 + doc/e.css | 428 +- doc/ecore.dox.in | 0 doc/examples.dox | 1692 ++ doc/foot.html | 21 +- doc/head.html | 109 +- 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 45897 -> 24099 bytes ecore-cocoa.pc.in | 11 + ecore-con.manifest | 5 + ecore-con.pc.in | 4 +- ecore-config.pc.in | 4 +- ecore-directfb.pc.in | 4 +- ecore-evas.manifest | 5 + ecore-evas.pc.in | 6 +- ecore-fb.manifest | 5 + ecore-fb.pc.in | 4 +- ecore-file.manifest | 5 + ecore-file.pc.in | 4 +- ecore-imf-evas.manifest | 5 + ecore-imf-evas.pc.in | 4 +- ecore-imf.manifest | 5 + ecore-imf.pc.in | 4 +- ecore-input-evas.manifest | 5 + ecore-input-evas.pc.in | 11 + ecore-input.manifest | 5 + ecore-input.pc.in | 11 + ecore-ipc.manifest | 5 + ecore-ipc.pc.in | 4 +- ecore-psl1ght.pc.in | 12 + ecore-sdl.pc.in | 4 +- ecore-wayland.pc.in | 12 + ecore-win32.pc.in | 5 +- ecore-wince.pc.in | 3 +- ecore-x.manifest | 5 + ecore-x.pc.in | 6 +- ecore.pc.in | 6 +- ecore.spec.in | 91 +- m4/ac_attribute.m4 | 51 +- m4/ac_path_generic.m4 | 137 + m4/check_x_extension.m4 | 43 +- m4/ecore_check_module.m4 | 156 +- 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 + packaging/ecore.changes | 3 + packaging/ecore.spec | 311 + 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/ko.po | 185 + po/nl.po | 175 + po/pt.po | 176 + po/sl.po | 175 + src/Makefile.am | 25 +- src/bin/Makefile.am | 21 +- src/bin/ecore_config.c | 42 +- 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 | 92 +- src/lib/ecore/Ecore.h | 2782 ++- src/lib/ecore/Ecore_Getopt.h | 419 + src/lib/ecore/Makefile.am | 73 +- src/lib/ecore/ecore.c | 810 +- src/lib/ecore/ecore_alloc.c | 132 + src/lib/ecore/ecore_anim.c | 590 +- src/lib/ecore/ecore_app.c | 49 +- src/lib/ecore/ecore_events.c | 801 +- src/lib/ecore/ecore_exe.c | 2225 ++- 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 | 185 +- src/lib/ecore/ecore_idle_exiter.c | 163 +- src/lib/ecore/ecore_idler.c | 175 +- src/lib/ecore/ecore_job.c | 125 + src/lib/ecore/ecore_main.c | 2312 ++- src/lib/ecore/ecore_pipe.c | 691 + src/lib/ecore/ecore_poll.c | 441 +- src/lib/ecore/ecore_private.h | 705 +- src/lib/ecore/ecore_signal.c | 671 +- src/lib/ecore/ecore_thread.c | 1611 ++ src/lib/ecore/ecore_throttle.c | 101 + src/lib/ecore/ecore_time.c | 166 +- src/lib/ecore/ecore_timer.c | 816 +- 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 | 2069 ++- src/lib/ecore_con/Ecore_Con_Eet.h | 73 + src/lib/ecore_con/Makefile.am | 58 +- src/lib/ecore_con/dns.c | 7878 ++++++++ src/lib/ecore_con/dns.h | 1074 ++ src/lib/ecore_con/ecore_con.c | 3477 ++-- 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 | 468 +- src/lib/ecore_con/ecore_con_eet.c | 796 + src/lib/ecore_con/ecore_con_info.c | 472 + 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 | 403 +- src/lib/ecore_con/ecore_con_socks.c | 940 + src/lib/ecore_con/ecore_con_ssl.c | 2115 +++ src/lib/ecore_con/ecore_con_url.c | 1935 +- src/lib/ecore_config/Makefile.am | 58 +- src/lib/ecore_config/ecore_config.c | 84 +- src/lib/ecore_config/ecore_config_db.c | 47 +- src/lib/ecore_config/ecore_config_extra.c | 53 +- src/lib/ecore_config/ecore_config_ipc_ecore.c | 47 +- src/lib/ecore_config/ecore_config_ipc_main.c | 30 +- src/lib/ecore_config/ecore_config_private.h | 40 +- src/lib/ecore_config/ecore_config_storage.c | 10 +- src/lib/ecore_config/ecore_config_util.c | 6 + src/lib/ecore_directfb/Ecore_DirectFB.h | 213 +- src/lib/ecore_directfb/Makefile.am | 15 +- src/lib/ecore_directfb/ecore_directfb.c | 1089 +- src/lib/ecore_directfb/ecore_directfb_keys.h | 359 +- src/lib/ecore_directfb/ecore_directfb_private.h | 57 +- src/lib/ecore_evas/Ecore_Evas.h | 2322 ++- src/lib/ecore_evas/Makefile.am | 101 +- src/lib/ecore_evas/ecore_evas.c | 3088 ++-- src/lib/ecore_evas/ecore_evas_buffer.c | 625 +- src/lib/ecore_evas/ecore_evas_cocoa.c | 584 + src/lib/ecore_evas/ecore_evas_directfb.c | 530 +- src/lib/ecore_evas/ecore_evas_ews.c | 1469 ++ src/lib/ecore_evas/ecore_evas_extn.c | 2247 +++ src/lib/ecore_evas/ecore_evas_fb.c | 718 +- src/lib/ecore_evas/ecore_evas_private.h | 423 +- src/lib/ecore_evas/ecore_evas_psl1ght.c | 515 + src/lib/ecore_evas/ecore_evas_sdl.c | 651 +- src/lib/ecore_evas/ecore_evas_util.c | 451 + src/lib/ecore_evas/ecore_evas_wayland_common.c | 657 + src/lib/ecore_evas/ecore_evas_wayland_egl.c | 434 + src/lib/ecore_evas/ecore_evas_wayland_shm.c | 657 + src/lib/ecore_evas/ecore_evas_win32.c | 1315 +- src/lib/ecore_evas/ecore_evas_wince.c | 1086 +- src/lib/ecore_evas/ecore_evas_x.c | 6314 ++++--- src/lib/ecore_fb/Ecore_Fb.h | 163 +- src/lib/ecore_fb/Makefile.am | 28 +- src/lib/ecore_fb/ecore_fb.c | 136 +- src/lib/ecore_fb/ecore_fb_kbd.c | 425 +- src/lib/ecore_fb/ecore_fb_keytable.h | 256 +- src/lib/ecore_fb/ecore_fb_li.c | 1078 +- src/lib/ecore_fb/ecore_fb_private.h | 78 +- src/lib/ecore_fb/ecore_fb_ps2.c | 254 +- src/lib/ecore_fb/ecore_fb_ts.c | 341 +- src/lib/ecore_fb/ecore_fb_vt.c | 404 +- src/lib/ecore_file/Ecore_File.h | 215 +- src/lib/ecore_file/Makefile.am | 27 +- src/lib/ecore_file/ecore_file.c | 1207 +- src/lib/ecore_file/ecore_file_download.c | 503 +- src/lib/ecore_file/ecore_file_monitor.c | 136 +- src/lib/ecore_file/ecore_file_monitor_inotify.c | 243 +- src/lib/ecore_file/ecore_file_monitor_poll.c | 405 +- src/lib/ecore_file/ecore_file_monitor_win32.c | 310 + src/lib/ecore_file/ecore_file_path.c | 186 +- src/lib/ecore_file/ecore_file_private.h | 115 +- src/lib/ecore_imf/Ecore_IMF.h | 844 +- src/lib/ecore_imf/Makefile.am | 27 +- src/lib/ecore_imf/ecore_imf.c | 38 +- src/lib/ecore_imf/ecore_imf_context.c | 1397 +- src/lib/ecore_imf/ecore_imf_module.c | 267 +- src/lib/ecore_imf/ecore_imf_private.h | 62 +- src/lib/ecore_imf_evas/Ecore_IMF_Evas.h | 23 +- src/lib/ecore_imf_evas/Makefile.am | 22 +- src/lib/ecore_imf_evas/ecore_imf_evas.c | 91 +- src/lib/ecore_input/Ecore_Input.h | 236 + 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 | 293 +- src/lib/ecore_ipc/Makefile.am | 33 +- src/lib/ecore_ipc/ecore_ipc.c | 1317 +- src/lib/ecore_ipc/ecore_ipc_private.h | 57 +- 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 | 68 +- src/lib/ecore_sdl/Ecore_Sdl_Keys.h | 111 +- src/lib/ecore_sdl/Makefile.am | 33 +- src/lib/ecore_sdl/ecore_sdl.c | 282 +- src/lib/ecore_sdl/ecore_sdl_private.h | 36 + src/lib/ecore_wayland/Ecore_Wayland.h | 391 + 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 | 1207 ++ 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 | 497 +- src/lib/ecore_win32/Makefile.am | 35 +- src/lib/ecore_win32/ecore_win32.c | 937 +- src/lib/ecore_win32/ecore_win32_cursor.c | 214 +- 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 | 931 +- src/lib/ecore_win32/ecore_win32_private.h | 107 +- src/lib/ecore_win32/ecore_win32_window.c | 1452 +- src/lib/ecore_wince/Ecore_WinCE.h | 289 +- src/lib/ecore_wince/Makefile.am | 28 +- src/lib/ecore_wince/ecore_wince.c | 485 +- src/lib/ecore_wince/ecore_wince_event.c | 1297 +- src/lib/ecore_wince/ecore_wince_private.h | 51 +- src/lib/ecore_wince/ecore_wince_window.c | 752 +- src/lib/ecore_x/Ecore_X.h | 3091 ++-- src/lib/ecore_x/Ecore_X_Atoms.h | 126 +- src/lib/ecore_x/Ecore_X_Cursor.h | 153 +- src/lib/ecore_x/Makefile.am | 16 +- src/lib/ecore_x/ecore_x_atoms_decl.h | 696 +- src/lib/ecore_x/xcb/Makefile.am | 155 +- src/lib/ecore_x/xcb/ecore_xcb.c | 2694 ++- src/lib/ecore_x/xcb/ecore_xcb_atoms.c | 149 + src/lib/ecore_x/xcb/ecore_xcb_composite.c | 306 +- src/lib/ecore_x/xcb/ecore_xcb_cursor.c | 556 +- src/lib/ecore_x/xcb/ecore_xcb_damage.c | 153 +- src/lib/ecore_x/xcb/ecore_xcb_dnd.c | 1101 +- src/lib/ecore_x/xcb/ecore_xcb_dpms.c | 433 +- src/lib/ecore_x/xcb/ecore_xcb_drawable.c | 152 +- src/lib/ecore_x/xcb/ecore_xcb_e.c | 1571 +- src/lib/ecore_x/xcb/ecore_xcb_error.c | 123 + src/lib/ecore_x/xcb/ecore_xcb_events.c | 4041 ++-- src/lib/ecore_x/xcb/ecore_xcb_extensions.c | 148 + src/lib/ecore_x/xcb/ecore_xcb_gc.c | 168 +- src/lib/ecore_x/xcb/ecore_xcb_gesture.c | 203 + src/lib/ecore_x/xcb/ecore_xcb_icccm.c | 3002 ++- src/lib/ecore_x/xcb/ecore_xcb_image.c | 738 + 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 | 143 +- src/lib/ecore_x/xcb/ecore_xcb_netwm.c | 3977 ++-- src/lib/ecore_x/xcb/ecore_xcb_pixmap.c | 41 +- src/lib/ecore_x/xcb/ecore_xcb_private.h | 677 +- src/lib/ecore_x/xcb/ecore_xcb_randr.c | 4061 +++- 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 | 540 +- src/lib/ecore_x/xcb/ecore_xcb_selection.c | 1520 +- src/lib/ecore_x/xcb/ecore_xcb_shape.c | 302 +- src/lib/ecore_x/xcb/ecore_xcb_sync.c | 389 +- 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 | 3029 +-- src/lib/ecore_x/xcb/ecore_xcb_window_prop.c | 1241 +- src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c | 393 +- 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 | 744 + src/lib/ecore_x/xcb/ecore_xcb_xinerama.c | 246 +- src/lib/ecore_x/xcb/ecore_xcb_xtest.c | 215 + src/lib/ecore_x/xlib/Makefile.am | 40 +- src/lib/ecore_x/xlib/ecore_x.c | 2100 ++- src/lib/ecore_x/xlib/ecore_x_atoms.c | 267 +- src/lib/ecore_x/xlib/ecore_x_composite.c | 163 +- src/lib/ecore_x/xlib/ecore_x_cursor.c | 355 +- src/lib/ecore_x/xlib/ecore_x_damage.c | 44 +- src/lib/ecore_x/xlib/ecore_x_dnd.c | 664 +- src/lib/ecore_x/xlib/ecore_x_dpms.c | 110 +- src/lib/ecore_x/xlib/ecore_x_drawable.c | 94 +- src/lib/ecore_x/xlib/ecore_x_e.c | 1616 +- src/lib/ecore_x/xlib/ecore_x_error.c | 77 +- src/lib/ecore_x/xlib/ecore_x_events.c | 3052 +-- src/lib/ecore_x/xlib/ecore_x_fixes.c | 250 +- src/lib/ecore_x/xlib/ecore_x_gc.c | 154 +- src/lib/ecore_x/xlib/ecore_x_gesture.c | 137 + src/lib/ecore_x/xlib/ecore_x_icccm.c | 1211 +- src/lib/ecore_x/xlib/ecore_x_image.c | 602 + src/lib/ecore_x/xlib/ecore_x_mwm.c | 128 +- src/lib/ecore_x/xlib/ecore_x_netwm.c | 1859 +- src/lib/ecore_x/xlib/ecore_x_pixmap.c | 44 +- src/lib/ecore_x/xlib/ecore_x_private.h | 295 +- src/lib/ecore_x/xlib/ecore_x_randr.c | 289 +- 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 | 2412 +++ 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 | 94 +- src/lib/ecore_x/xlib/ecore_x_selection.c | 714 +- src/lib/ecore_x/xlib/ecore_x_sync.c | 135 +- src/lib/ecore_x/xlib/ecore_x_test.c | 191 +- src/lib/ecore_x/xlib/ecore_x_vsync.c | 351 + src/lib/ecore_x/xlib/ecore_x_window.c | 1351 +- src/lib/ecore_x/xlib/ecore_x_window_prop.c | 694 +- src/lib/ecore_x/xlib/ecore_x_window_shape.c | 633 +- src/lib/ecore_x/xlib/ecore_x_xi2.c | 556 + src/lib/ecore_x/xlib/ecore_x_xinerama.c | 89 +- 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 | 822 + 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 + 456 files changed, 200995 insertions(+), 40806 deletions(-) create mode 100644 README create mode 100644 configure.ac create mode 100644 debian/changelog mode change 100644 => 100755 debian/control create mode 100644 debian/jobs create mode 100644 debian/libecore-con-svn-01.install create mode 100644 debian/libecore-con-svn-01.shlibs create mode 100644 debian/libecore-con.install create mode 100644 debian/libecore-config-svn-01.install create mode 100644 debian/libecore-config-svn-01.shlibs create mode 100644 debian/libecore-config.install mode change 100644 => 100755 debian/libecore-dev.install create mode 100644 debian/libecore-doc.doc-base create mode 100644 debian/libecore-evas-svn-01.install create mode 100644 debian/libecore-evas-svn-01.shlibs create mode 100644 debian/libecore-evas.install create mode 100644 debian/libecore-fb-svn-01.install create mode 100644 debian/libecore-fb-svn-01.shlibs create mode 100644 debian/libecore-fb.install create mode 100644 debian/libecore-file-svn-01.install create mode 100644 debian/libecore-file-svn-01.shlibs create mode 100644 debian/libecore-file.install create mode 100644 debian/libecore-imf-svn-01.install create mode 100644 debian/libecore-imf-svn-01.shlibs create mode 100644 debian/libecore-imf.install create mode 100644 debian/libecore-input-svn-01.install create mode 100644 debian/libecore-input-svn-01.shlibs create mode 100644 debian/libecore-input.install create mode 100644 debian/libecore-ipc-svn-01.install create mode 100644 debian/libecore-ipc-svn-01.shlibs create mode 100644 debian/libecore-ipc.install create mode 100644 debian/libecore-svn-01.install create mode 100644 debian/libecore-svn-01.shlibs create mode 100644 debian/libecore-x-svn-01.install create mode 100644 debian/libecore-x-svn-01.shlibs create mode 100644 debian/libecore-x.install create mode 100644 debian/libecore.install mode change 100644 => 100755 debian/rules create mode 100644 doc/Doxyfile.in create mode 100644 doc/Makefile.am create mode 100644 doc/ecore.dox.in create mode 100644 doc/examples.dox 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 ecore-cocoa.pc.in create mode 100644 ecore-con.manifest create mode 100644 ecore-evas.manifest create mode 100644 ecore-fb.manifest create mode 100644 ecore-file.manifest create mode 100644 ecore-imf-evas.manifest create mode 100644 ecore-imf.manifest create mode 100644 ecore-input-evas.manifest create mode 100644 ecore-input-evas.pc.in create mode 100644 ecore-input.manifest create mode 100644 ecore-input.pc.in create mode 100644 ecore-ipc.manifest create mode 100644 ecore-psl1ght.pc.in create mode 100644 ecore-wayland.pc.in create mode 100644 ecore-x.manifest create mode 100644 m4/ac_path_generic.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 packaging/ecore.changes create mode 100644 packaging/ecore.spec 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/ko.po create mode 100644 po/nl.po create mode 100644 po/pt.po create mode 100644 po/sl.po 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/ecore/Ecore_Getopt.h create mode 100644 src/lib/ecore/ecore_alloc.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_job.c create mode 100644 src/lib/ecore/ecore_pipe.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_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_Eet.h 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_alloc.c create mode 100644 src/lib/ecore_con/ecore_con_ares.c create mode 100644 src/lib/ecore_con/ecore_con_eet.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_socks.c create mode 100644 src/lib/ecore_con/ecore_con_ssl.c create mode 100644 src/lib/ecore_evas/ecore_evas_cocoa.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_psl1ght.c create mode 100644 src/lib/ecore_evas/ecore_evas_util.c create mode 100644 src/lib/ecore_evas/ecore_evas_wayland_common.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_file/ecore_file_monitor_win32.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_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_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 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_x/xcb/ecore_xcb_atoms.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_error.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_extensions.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_gesture.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_region.c create mode 100644 src/lib/ecore_x/xcb/ecore_xcb_render.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_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_xtest.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_gesture.c create mode 100644 src/lib/ecore_x/xlib/ecore_x_image.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_vsync.c create mode 100755 src/lib/ecore_x/xlib/ecore_x_xi2.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/AUTHORS b/AUTHORS index 4968fd8..ff9f752 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,4 @@ +Myoungwoon Roy Kim(roy_kim) The Rasterman Tom Gilbert Burra @@ -11,7 +12,7 @@ Howell Tam Nathan Ingersoll Andrew Elcock Kim Woelders -Sebastian Dransfeld +Sebastian Dransfeld Simon Poole Jorge Luis Zapata Muga dan sinclair @@ -19,3 +20,38 @@ 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 +Seong-ho Cho (DarkCircle) +Patryk Kaczmarek +Daniel Willmann diff --git a/COPYING b/COPYING index dee3047..fb8c49d 100644 --- a/COPYING +++ b/COPYING @@ -1,20 +1,25 @@ -Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) +Copyright notice for Ecore: -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 of the Software, its documentation and marketing & publicity -materials, and acknowledgment shall be given in the documentation, materials -and software packages that this Software was used. - -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 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. +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 index ee16b53..d9f5d9b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,997 @@ -Wed Jun 8 16:56:30 2005 Michael Jennings (mej) +2011-01-29 Carsten Haitzler (The Rasterman) -Fix spec file. ----------------------------------------------------------------------- + 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. + +2012-08-30 Carsten Haitzler (The Rasterman) + + 1.7.0 release + +2012-08-31 Cedric Bail + + * Add Ecore_Con_Eet API to help using Eet_Data with Ecore_Con + +2012-09-03 Shinwoo Kim (kimcinoo) + + * Add ecore_x illume access messages: + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP + ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN + +2012-09-04 Jihoon Kim (jihoon) + + * Add ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN + +2012-09-05 Mike Blumenkrantz + + * Fix crash that could occur in ecore_con_ssl with privkeys and certificates on failure + +2012-09-06 Mike Blumenkrantz + + * Fix race condition in ecore-con where events could sometimes be sent for freed clients + * Fix ssl servers using openssl + * Fix ssl connections overall + +2012-09-07 Christopher Michael + + * Fix ecore_x_randr to actually return outputs properly. + +2012-09-08 Vincent Torri + + * Fix readlink usage in ecore_file. + +2012-09-12 Jihoon Kim (jihoon) + + * Add ECORE_IMF_PREEDIT_TYPE_SUB4~7 style. + +2012-09-10 Christopher Michael + + * Fix ecore_x_randr to actually return crtcs properly. + +2012-09-11 Christopher Michael + + * Fix ecore_x_randr to actually return crtcs possible outputs properly. + * Fix ecore_x_randr to actually return crtcs outputs properly. + +2012-09-13 Mike Blumenkrantz + + * Return -1 for ecore_con_server_fd_get() in the case that the server has already been deleted + +2012-09-13 Carsten Haitzler (The Rasterman) + + * Fix ecore-evas rotation handling for canvases that shows up + only on some drivers and GL implementations. + +2012-09-14 Doyoun Kang + + * Add string to atom_items for ECORE_X_ATOM_E_ILLUME_WINDOW_STATE, + ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL, ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING + +2012-09-18 Patryk Kaczmarek + + * Fix escaping in ecore_file_escape_name() to handle tab and + newline right. + +2012-09-21 Carsten Haitzler (The Rasterman) + + * Fix ecore_x_image_is_argb32_get() to return correctly on + endianess. + +2012-09-21 Christopher Michael + + * Fix ecore_x_randr to properly return output modes from + ecore_x_randr_output_modes_get(). + +2012-09-27 Carsten Haitzler (The Rasterman) + + * Fix ecore_imf buf in the ibus module where it may segv + accessing a wrong context handle. + +2012-10-02 Daniel Willmann + + * Fix memory allocation size in ecore_thread_feedback() + +2012-10-03 Daniel Wilmann + * Fix memory allocation size in ecore_x xcb randr function + +2012-10-04 Cedric Bail + + * Add ecore_x_input_raw_select and ECORE_X_RAW_*. + +2012-10-04 Sebastian Dransfeld + + * Expose ecore_x_selection_converter_text + +2012-10-05 Cedric Bail + + * Properly reschedule call to curl. + +2012-10-05 Eduardo Lima (Etrunko) + + * Wayland SHM now features a mechanism to synchronize rendering with + the compositor, removing tearing effect in animations when using that + engine. diff --git a/INSTALL b/INSTALL index 3a3ad7e..23e5f25 100644 --- a/INSTALL +++ b/INSTALL @@ -1,14 +1,236 @@ -COMPILING and INSTALLING: +Installation Instructions +************************* -If you got a official release tar archive do: - ./configure - -( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) - -Then to compile: - make +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. -To install (run this as root, or the user who handles installs): - make install +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. -NOTE: You MUST make install Eet for it to run properly. diff --git a/Makefile.am b/Makefile.am index f373799..9f16aeb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,129 +2,249 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src - -MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ - config.h.in config.sub configure install-sh \ - ltconfig ltmain.sh missing mkinstalldirs \ - stamp-h.in build-stamp configure-stamp depcomp \ - ecore_docs.tar.gz ecore.c \ - README \ - ecore.spec \ - ecore-con.pc \ - ecore-config.pc \ - ecore-desktop.pc \ - ecore-directfb.pc\ - ecore-evas.pc \ - ecore-fb.pc \ - ecore-file.pc \ - ecore-imf.pc \ - ecore-imf-evas.pc \ - ecore-ipc.pc \ - ecore-job.pc \ - ecore-txt.pc \ - ecore-x.pc \ - ecore-win32.pc \ - ecore-sdl.pc \ - ecore-wince.pc \ - ecore.pc +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 COPYING-PLAIN \ - autogen.sh ecore.c.in gendoc ecore.supp \ - Doxyfile \ - ecore.pc.in \ - ecore-con.pc.in \ - ecore-config.pc.in \ - ecore-desktop.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-job.pc.in \ - ecore-txt.pc.in \ - ecore-x.pc.in \ - ecore-win32.pc.in \ - ecore-sdl.pc.in \ - ecore-wince.pc.in \ - ecore.spec.in ecore.spec \ - doc gendoc +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 -pcon = ecore-con.pc +pkgconfig_DATA += ecore-con.pc endif if BUILD_ECORE_CONFIG -pconfig = ecore-config.pc +pkgconfig_DATA += ecore-config.pc endif if BUILD_ECORE_DIRECTFB -pdfb = ecore-directfb.pc +pkgconfig_DATA += ecore-directfb.pc endif if BUILD_ECORE_EVAS -pevas = ecore-evas.pc +pkgconfig_DATA += ecore-evas.pc endif if BUILD_ECORE_FB -pfb = ecore-fb.pc +pkgconfig_DATA += ecore-fb.pc endif if BUILD_ECORE_FILE -pfile = ecore-file.pc -endif - -if BUILD_ECORE_DESKTOP -pdesktop = ecore-desktop.pc +pkgconfig_DATA += ecore-file.pc endif if BUILD_ECORE_IMF -pimf = ecore-imf.pc +pkgconfig_DATA += ecore-imf.pc endif if BUILD_ECORE_IMF_EVAS -pimfevas = ecore-imf-evas.pc +pkgconfig_DATA += ecore-imf-evas.pc endif -if BUILD_ECORE_IPC -pipc = ecore-ipc.pc +if BUILD_ECORE_INPUT +pkgconfig_DATA += ecore-input.pc endif -if BUILD_ECORE_JOB -pjob = ecore-job.pc +if BUILD_ECORE_INPUT_EVAS +pkgconfig_DATA += ecore-input-evas.pc endif -if BUILD_ECORE_TXT -ptxt = ecore-txt.pc +if BUILD_ECORE_IPC +pkgconfig_DATA += ecore-ipc.pc endif if BUILD_ECORE_X -px = ecore-x.pc +pkgconfig_DATA += ecore-x.pc endif if BUILD_ECORE_WIN32 -pwin32 = ecore-win32.pc +pkgconfig_DATA += ecore-win32.pc endif if BUILD_ECORE_WINCE -pwince = ecore-wince.pc +pkgconfig_DATA += ecore-wince.pc endif - if BUILD_ECORE_SDL -psdl = ecore-sdl.pc +pkgconfig_DATA += ecore-sdl.pc endif -if BUILD_ECORE_X_XCB -px = ecore-x.pc +if BUILD_ECORE_COCOA +pkgconfig_DATA += ecore-cocoa.pc endif -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = \ - ecore.pc $(pcon) $(pconfig) $(pdfb) $(pevas) \ - $(pfb) $(pfile) $(pdesktop) $(pimf) $(pimfevas) $(pipc) $(pjob) $(ptxt) \ - $(px) $(pwin32) $(pwince) $(psdl) +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 index e69de29..f08395d 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,326 @@ +Ecore 1.8.0 + +Changes since Ecore 1.7.0: +-------------------------- + +Additions: + * ecore_con: + - Add Ecore_Con_Eet API to help using Eet_Data with Ecore_Con. + * ecore_x: + - ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP. + - ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN. + - ecore_x_input_raw_select. + - +ecore_x_selection_converter_text. + - ECORE_X_RAW_MOTION, ECORE_X_RAW_BUTTON_PRESS and ECORE_X_RAW_BUTTON_RELEASE. + * ecore_imf: + - ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN. + - ECORE_IMF_PREEDIT_TYPE_SUB4~7 style. + * ecore_evas: + - Wayland SHM engine now features a mechanism to synchronize rendering with + the compositor, removing the tearing effect in animations when using that + engine. + +Fixes: + * ecore_con_url: + - Timeouts are handled correctly now (passing HTTP status 408 to + completion callback). + - properly reschedule call to curl. + * ecore_evas rotation handling on some driver implementations + * ecore_file_escape_name() escape taba nd newline right. + * ecore_imf ibus module potential segv fixed. + * ecore_thread_feedback() memory allocation and corruption fixed. + * ecore_x: + - ecore_x_image_is_argb32_get() returns correctly given endianness. + - ecore_x_randr to actually return outputs properly. + - ecore_x_randr to actually return crtcs properly. + - ecore_x_randr to actually return crtcs possible outputs properly. + - ecore_x_randr to actually return crtcs outputs properly. + +Improvements: + +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..e9cedf3 --- /dev/null +++ b/README @@ -0,0 +1,98 @@ +Ecore 1.7.99 + +****************************************************************************** + + 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 index 995ff2f..81e1956 100755 --- a/autogen.sh +++ b/autogen.sh @@ -3,14 +3,38 @@ rm -rf autom4te.cache rm -f aclocal.m4 ltmain.sh -touch README +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 "$@" + ./configure -C "$@" fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..2a6c8d7 --- /dev/null +++ b/configure.ac @@ -0,0 +1,2271 @@ +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## +m4_define([v_maj], [1]) +m4_define([v_min], [7]) +m4_define([v_mic], [99]) +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 +dnl 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_con_eet="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_con_eet="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_CHECK_X_EXTENSION([Xi2_2], [XInput2.h], [Xi], [XIGrabTouchBegin], [$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" +have_ecore_con_eet="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 + + if test "x${have_eet}" = "xyes" ; then + requirements_ecore_con="eet > 1.7 ${requirements_ecore_con}" + have_ecore_con_eet="yes" + AC_DEFINE(ECORE_HAVE_EET, 1, [Define if Ecore_Con Eet_Connection helper is supported]) + fi + + 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 +AM_CONDITIONAL([HAVE_IPV6], [test "x${have_ipv6}" = "xyes"]) +AM_CONDITIONAL([ECORE_HAVE_EET], [test "x${have_ecore_con_eet}" = "xyes"]) + +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 " Eet........................: $have_ecore_con_eet" + 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" + echo " Xi2.2......................: $use_xi2_2" + 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/debian/changelog b/debian/changelog new file mode 100644 index 0000000..e01452c --- /dev/null +++ b/debian/changelog @@ -0,0 +1,1346 @@ +ecore (1.2.0+svn.72988slp2+build02) unstable; urgency=low + + * [ecore_x] Add missing features in Ecore_X.h + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.72988slp2+build02 + + -- Doyoun Kang Thu, 05 Jul 2012 16:22:21 +0900 + +ecore (1.2.0+svn.72988slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.72988slp2+build01 + + -- Jiyoun Park Wed, 04 Jul 2012 18:31:50 +0900 + +ecore (1.2.0+svn.70444slp2+build06) unstable; urgency=low + + * Added per-window profile feature to support multi-head display. + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build06 + + -- Gwanglim Lee Tue, 19 Jun 2012 18:34:11 +0900 + +ecore (1.2.0+svn.70444slp2+build05) unstable; urgency=low + + * Add feature - floating mode (app-in-app) + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build05 + + -- Doyoun Kang Tue, 05 Jun 2012 15:17:17 +0900 + +ecore (1.2.0+svn.70444slp2+build04) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build04 + + -- Jiyoun Park Tue, 29 May 2012 17:07:07 +0900 + +ecore (1.2.0+svn.70444slp2+build03) unstable; urgency=low + + * add disable-ecore-imf-xim option + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build03 + + -- Jihoon Kim Tue, 22 May 2012 16:05:56 +0900 + +ecore (1.2.0+svn.70444slp2+build02) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build02 + + -- Myungjae Lee Wed, 25 Apr 2012 17:28:30 +0900 + +ecore (1.2.0+svn.70444slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70444slp2+build01 + + -- Myungjae Lee Wed, 25 Apr 2012 15:13:33 +0900 + +ecore (1.2.0+svn.70302slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70302slp2+build01 + + -- Jaehwan Kim Mon, 23 Apr 2012 15:28:49 +0900 + +ecore (1.2.0+svn.70251slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70251slp2+build01 + + -- Hyoyoung Chang Wed, 18 Apr 2012 18:03:09 +0900 + +ecore (1.2.0+svn.70159slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.70159slp2+build01 + + -- Jiyoun Park Fri, 13 Apr 2012 18:31:50 +0900 + +ecore (1.2.0+svn.69928slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.2.0+svn.69928slp2+build01 + + -- Jeonghyun Yun Fri, 06 Apr 2012 18:14:52 +0900 + +ecore (1.1.0+svn.69655slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69655slp2+build01 + + -- Jeonghyun Yun Wed, 28 Mar 2012 14:28:49 +0900 + +ecore (1.1.0+svn.69424slp2+build03) unstable; urgency=low + + * [ECORE_X] remove feature - illume window state for app-in-app + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69424slp2+build03 + + -- Doyoun Kang Mon, 26 Mar 2012 13:56:33 +0900 + +ecore (1.1.0+svn.69424slp2+build02) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69424slp2+build02 + + -- Jeonghyun Yun Sun, 18 Mar 2012 14:02:16 +0900 + +ecore (1.1.0+svn.69424slp2+build01) unstable; urgency=low + + * EFL migration + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69424slp2+build01 + + -- Jeonghyun Yun Fri, 16 Mar 2012 21:50:01 +0900 + +ecore (1.1.0+svn.69115slp2+build04) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69115slp2+build04 + + -- WooHyun Jung Thu, 15 Mar 2012 21:23:10 +0900 + +ecore (1.1.0+svn.69115slp2+build03) unstable; urgency=low + + * [Ecore_X] Remove unused APIs, unused Atoms and duplicated Atoms + - ecore_x_e_comp_dri_buff_flip_supported_set + - ecore_x_e_comp_dri_buff_flip_supported_get + - ECORE_X_ATOM_E_USER_CREATED_WINDOW + - ECORE_X_ATOM_E_PARENT_BORDER_WINDOW + - ECORE_X_ATOM_E_COMP_DRI_BUFF_FLIP_SUPPORTED + - ECORE_X_ATOM_E_ILLUME_ROTATE_OPERATOR + - ECORE_X_ATOM_USER_CREATED_WINDOW + - ECORE_X_ATOM_PARENT_BORDER_WINDOW + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69115slp2+build03 + + -- Doyoun Kang Wed, 14 Mar 2012 09:01:03 +0900 + +ecore (1.1.0+svn.69115slp2+build02) unstable; urgency=low + + * Change parameter of ecore_imf_context_input_panel_language_locale_get + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69115slp2+build02 + + -- Jihoon Kim Mon, 12 Mar 2012 14:43:53 +0900 + +ecore (1.1.0+svn.69115slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.69115slp2+build01 + + -- Jeonghyun Yun Sat, 10 Mar 2012 13:51:23 +0900 + +ecore (1.1.0+svn.68762slp2+build02) unstable; urgency=low + + * 69115 + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.68762slp2+build02 + + -- Jeonghyun Yun Sat, 10 Mar 2012 13:20:45 +0900 + +ecore (1.1.0+svn.68762slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.68762slp2+build01 + + -- Jeonghyun Yun Wed, 07 Mar 2012 16:44:23 +0900 + +ecore (1.1.0+svn.68529slp2+build01) unstable; urgency=low + + * Package upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.68529slp2+build01 + + -- Jeonghyun Yun Fri, 02 Mar 2012 06:32:15 -0500 + +ecore (1.1.0+svn.67695slp2+build06) unstable; urgency=low + + * [ecore_imf] add language_locale_get, candidate_panel_geometry_get API + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build06 + + -- Jihoon Kim Fri, 02 Mar 2012 11:44:15 +0900 + +ecore (1.1.0+svn.67695slp2+build05) unstable; urgency=low + + * [ecore_imf] add ecore_imf_context_input_panel_caps_lock_mode_set/get + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build05 + + -- Jihoon Kim Wed, 29 Feb 2012 14:21:16 +0900 + +ecore (1.1.0+svn.67695slp2+build04) unstable; urgency=low + + * [ecore_imf] cleanup code + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build04 + + -- Jihoon Kim Thu, 23 Feb 2012 17:36:50 +0900 + +ecore (1.1.0+svn.67695slp2+build03) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build03 + + -- ChunEon Park Mon, 20 Feb 2012 20:15:54 +0900 + +ecore (1.1.0+svn.67695slp2+build02) unstable; urgency=low + + * Add APIs related to input panel control + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build02 + + -- Jihoon Kim Mon, 20 Feb 2012 09:23:47 +0900 + +ecore (1.1.0+svn.67695slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.67695slp2+build01 + + -- Jaehwan Kim Wed, 15 Feb 2012 19:01:02 +0900 + +ecore (1.1.0+svn.66972slp2+build03) unstable; urgency=low + + * [ECORE_X] Add feature - illume window state for app-in-app + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.66972slp2+build03 + + -- Doyoun Kang Thu, 02 Feb 2012 15:04:12 +0900 + +ecore (1.1.0+svn.66972slp2+build02) unstable; urgency=low + + * Use synchronous ecore_imf callback API + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.66972slp2+build02 + + -- Jihoon Kim Tue, 31 Jan 2012 13:21:06 +0900 + +ecore (1.1.0+svn.66972slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.66972slp2+build01 + + -- Jaehwan Kim Mon, 16 Jan 2012 18:29:42 +0900 + +ecore (1.1.0+svn.65878slp2+build05) unstable; urgency=low + + * jpeg7 -> jpeg8 + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65878slp2+build05 + + -- ChunEon Park Mon, 16 Jan 2012 11:14:18 +0900 + +ecore (1.1.0+svn.65878slp2+build04) unstable; urgency=low + + * Repackaging + * Git: slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65878slp2+build04 + + -- ChunEon Park Fri, 30 Dec 2011 15:07:27 +0900 + +ecore (1.1.0+svn.65878slp2+build03) unstable; urgency=low + + * Just Bumped up version + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65878slp2+build03 + + -- Tae-Hwan Kim Mon, 26 Dec 2011 15:20:31 +0900 + +ecore (1.1.0+svn.65878slp2+build02) unstable; urgency=low + + * Upstream sync related ecore_con (r66414, 66462, sync after r65934) + * ecore_timer_dump is disabled as default + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65878slp2+build02 + + -- Tae-Hwan Kim Fri, 23 Dec 2011 18:07:06 +0900 + +ecore (1.1.0+svn.65878slp2+build01) unstable; urgency=low + + * Package Upload for migration + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65878slp2+build01 + + -- Jaehwan Kim Thu, 08 Dec 2011 13:51:03 +0900 + +ecore (1.1.0+svn.65618slp2+build02) unstable; urgency=low + + * [Bug Fix] CQ H0100136744 - curl fd handler refactoring + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65618slp2+build02 + + -- Tae-Hwan Kim Tue, 29 Nov 2011 17:43:36 +0900 + +ecore (1.1.0+svn.65618slp2+build01) unstable; urgency=low + + * Package Upload + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65618slp2+build01 + + -- Jaehwan Kim Tue, 29 Nov 2011 14:11:22 +0900 + +ecore (1.1.0+svn.65303slp2+build04) unstable; urgency=low + + * Add a configure option to enable ecore x gesture extension support + * Add libxgesture-dev on Build-Depends section in debian/control + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65303slp2+build04 + + -- Sung-Jin Park Fri, 18 Nov 2011 11:11:27 +0900 + +ecore (1.1.0+svn.65303slp2+build03) unstable; urgency=low + + * Package Upload : because of build error + * Important Changes + Rollback about dependency with cares - Caused some app's build error about no Elementary.h + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.1.0+svn.65303slp2+build03 + + -- WooHyun Jung Thu, 17 Nov 2011 19:10:33 +0900 + +ecore (1.1.0+svn.65303slp2+build02) unstable; urgency=low + + * Enable c-ARES based aync DNS resolution + + -- Mike McCormack Thu, 17 Nov 2011 17:46:57 +0900 + +ecore (1.1.0+svn.65303slp2+build01) unstable; urgency=low + + * Merge with upstream @65303 + + -- Mike McCormack Thu, 17 Nov 2011 09:05:24 +0900 + +ecore (1.0.0.001+svn.64964slp2+build02) unstable; urgency=low + + * [ecore_imf] remove unused interfaces + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.64964slp2+build02 + + -- Jihoon Kim Mon, 14 Nov 2011 15:19:52 +0900 + +ecore (1.0.0.001+svn.64964slp2+build01) unstable; urgency=low + + * Merge with upstream @64964 + + -- Mike McCormack Thu, 10 Nov 2011 12:12:11 +0900 + +ecore (1.0.0.001+svn.64661slp2+build04) unstable; urgency=low + + * [ecore_imf] remove depecated APIs + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.64661slp2+build04 + + -- Jihoon Kim Thu, 10 Nov 2011 09:28:41 +0900 + +ecore (1.0.0.001+svn.64661slp2+build03) unstable; urgency=low + + * Ecore, Ecore_con, Ecore_file: merge upstream r64851 + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.64661slp2+build03 + + -- Tae-Hwan Kim Tue, 08 Nov 2011 14:17:28 +0900 + +ecore (1.0.0.001+svn.64661slp2+build02) unstable; urgency=low + + * [ecore evas] fix rotation lockup problem + when application's window is unmapped + * [ecore evas] fix sync counter lockup problem with application + which rapidly maps and unmaps a window + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.64661slp2+build02 + + -- Gwanglim Lee Fri, 04 Nov 2011 13:45:05 +0900 + +ecore (1.0.0.001+svn.64661slp2+build01) unstable; urgency=low + + * Merge with upstream @64661 + + -- Mike McCormack Thu, 03 Nov 2011 11:19:25 +0900 + +ecore (1.0.0.001+svn.63888slp2+build07) unstable; urgency=low + + * [ecore con url] Change HTTP persistent --> normal + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build07 + + -- Tae-Hwan Kim Wed, 02 Nov 2011 17:56:11 +0900 + +ecore (1.0.0.001+svn.63888slp2+build06) unstable; urgency=low + + * Deprecated some Ecore_IMF APIs + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build06 + + -- Jihoon Kim Wed, 02 Nov 2011 12:41:49 +0900 + +ecore (1.0.0.001+svn.63888slp2+build05) unstable; urgency=low + + * Upload package + * Important Changes + Add new api related with get last recently requested geometry value + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build05 + + -- Jiyoun Park Mon, 31 Oct 2011 15:23:33 +0900 + +ecore (1.0.0.001+svn.63888slp2+build04) unstable; urgency=low + + * Package Upload + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build04 + + -- Tae-Hwan Kim Mon, 31 Oct 2011 10:25:07 +0900 + +ecore (1.0.0.001+svn.63888slp2+build03) unstable; urgency=low + + * Upload package + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build03 + + -- Jihoon Kim Tue, 25 Oct 2011 20:51:15 +0900 + +ecore (1.0.0.001+svn.63888slp2+build02) unstable; urgency=low + + * Upload Package + * Important Changes + ecore evas util can send resize request even though X relpy + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build02 + + -- Jiyoun Park Tue, 25 Oct 2011 18:08:02 +0900 + +ecore (1.0.0.001+svn.63888slp2+build01) unstable; urgency=low + + * Merge with upstream + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63888slp2+build01 + + -- Mike McCormack Fri, 07 Oct 2011 11:41:21 +0900 + +ecore (1.0.0.001+svn.63811slp2+build01) unstable; urgency=low + + * merge with upstream + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.63811slp2+build01 + + -- Mike McCormack Wed, 05 Oct 2011 15:34:39 +0900 + +ecore (1.0.0.001+svn.62653slp2+build02) unstable; urgency=low + + * [SVN patch] ecore in SLP is merged with SVN r63475 patch only. + - fix bug in generic event handling on xlib side of ecore_x + * Ecore_IMF: remove unused enum ECORE_IMF_Autocorrection + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.62653slp2+build02 + + -- Doyoun Kang Mon, 26 Sep 2011 20:01:42 +0900 + +ecore (1.0.0.001+svn.62653slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r62653 + * Important Changes + [Migration upstream r62653] Merge branch 'svn_merge' + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.62653slp2+build01 + + -- Jaehwan Kim Fri, 02 Sep 2011 18:43:09 +0900 + +ecore (1.0.0.001+svn.61784slp2+build02) unstable; urgency=low + + * [ecore_x] fixed multi-touch double clicked + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.61784slp2+build02 + + -- ChunEon Park Wed, 31 Aug 2011 19:42:43 +0900 + +ecore (1.0.0.001+svn.61784slp2+build01) unstable; urgency=low + + * Merge with upstream ecore svn @61784 + + -- Mike McCormack Wed, 27 Jul 2011 14:43:58 +0900 + +ecore (1.0.0.001+svn.61150slp2+build03) unstable; urgency=low + + * [ecore_imf] set autocapital type + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.61150slp2+build03 + + -- Jihoon Kim Mon, 25 Jul 2011 14:30:29 +0900 + +ecore (1.0.0.001+svn.61150slp2+build02) unstable; urgency=low + + * [ecore_imf] add ecore_imf_context_cursor_location_set API + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.61150slp2+build02 + + -- Jihoon Kim Mon, 11 Jul 2011 16:13:56 +0900 + +ecore (1.0.0.001+svn.61150slp2+build01) unstable; urgency=low + + * Merge with SVN revision 61150 + + -- Mike McCormack Thu, 07 Jul 2011 15:10:51 +0900 + +ecore (1.0.0.001+svn.60286slp2+build02) unstable; urgency=low + + * [ecore_imf] add ecore_imf_context_input_panel_enalbed_set, get API + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.60286slp2+build02 + + -- Jihoon Kim Sat, 25 Jun 2011 15:11:35 +0900 + +ecore (1.0.0.001+svn.60286slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r60286 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.60286slp2+build01 + + -- Jaehwan Kim Fri, 24 Jun 2011 18:10:02 +0900 + +ecore (1.0.0.001+svn.58224slp2+build04) unstable; urgency=low + + * Fixed _ecore_main_loop_iterate_internal. Upstream merge. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58224slp2+build04 + + -- Daniel Juyung Seo Mon, 23 May 2011 14:20:58 +0900 + +ecore (1.0.0.001+svn.58224slp2+build03) unstable; urgency=low + + * Package upload + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58224slp2+build03 + + -- Jaehwan Kim Tue, 03 May 2011 20:48:31 +0900 + +ecore (1.0.0.001+svn.58224slp2+build02) unstable; urgency=low + + * Add shape input mask feature (upstream svn rev.58621) + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58224slp2+build02 + + -- Doyoun Kang Mon, 11 Apr 2011 12:52:50 +0900 + +ecore (1.0.0.001+svn.58224slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r58224 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58224slp2+build01 + + -- Jaehwan Kim Tue, 05 Apr 2011 15:55:04 +0900 + +ecore (1.0.0.001+svn.58047slp2+build02) unstable; urgency=low + + * Rollback + * Git: slp-scm.sec.samsung.net:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58047slp2+build02 + + -- Shinwoo Kim Tue, 29 Mar 2011 23:52:57 +0900 + +ecore (1.0.0.001+svn.58047slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r58047 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.58047slp2+build01 + + -- Shinwoo Kim Tue, 29 Mar 2011 18:55:29 +0900 + +ecore (1.0.0.001+svn.57453slp2+build05) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r57453 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.57453slp2+build05 + + -- Myungjae Lee Wed, 09 Mar 2011 11:29:41 +0900 + +ecore (1.0.0.001+svn.57453slp2+build04) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r57453 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.57453slp2+build04 + + -- Myungjae Lee Wed, 09 Mar 2011 11:14:55 +0900 + +ecore (1.0.0.001+svn.57453slp2+build03) unstable; urgency=low + + * Package Uplaod : Rollback + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.57453slp2+build03 + + -- WooHyun Jung Tue, 08 Mar 2011 12:38:42 +0900 + +ecore (1.0.0.001+svn.57453slp2+build02) unstable; urgency=low + + * Package Upload : rollback + * Git: 165.213.180.234:/slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.57453slp2+build02 + + -- WooHyun Jung Tue, 08 Mar 2011 11:10:05 +0900 + +ecore (1.0.0.001+svn.57453slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r57453 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.57453slp2+build01 + + -- Myungjae Lee Mon, 07 Mar 2011 17:28:10 +0900 + +ecore (1.0.0.001+svn.56239slp2+build06) unstable; urgency=low + + * [SVN r56251] Bug fix - dont call pipe handler if its deleted. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build06 + + -- WooHyun Jung Fri, 11 Feb 2011 17:52:58 +0900 + +ecore (1.0.0.001+svn.56239slp2+build05) unstable; urgency=low + + * [SVN r56251] Bug fix - dont call pipe handler if its deleted. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build05 + + -- Myoungwoon Kim Tue, 08 Feb 2011 15:21:18 +0900 + +ecore (1.0.0.001+svn.56239slp2+build04) unstable; urgency=low + + * [ecore_evas_x.c] apply ECORE_EVAS_GL_SYNC_DRAW_DONE env. + + check whether GL driver sends SYNC_DRAW_DONE msg after buffer copy. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build04 + + -- Gwanglim Lee Sat, 05 Feb 2011 17:29:55 +0900 + +ecore (1.0.0.001+svn.56239slp2+build03) unstable; urgency=low + + * ee->no_comp_sync = 0 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build03 + + -- WooHyun Jung Mon, 31 Jan 2011 18:26:53 +0900 + +ecore (1.0.0.001+svn.56239slp2+build02) unstable; urgency=low + + * ee->no_comp_sync = 0 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build02 + + -- WooHyun Jung Mon, 31 Jan 2011 17:12:38 +0900 + +ecore (1.0.0.001+svn.56239slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r56239 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56239slp2+build01 + + -- WooHyun Jung Thu, 27 Jan 2011 12:21:58 +0900 + +ecore (1.0.0.001+svn.56091slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r56091 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56091slp2+build01 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.56091slp2+build01 + + -- WooHyun Jung Wed, 19 Jan 2011 16:16:45 +0900 + +ecore (1.0.0.001+svn.55755slp2+build02) unstable; urgency=low + + * [ecore_imf] bug fix : hide keyboard in ecore_imf_context_del + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55755slp2+build02 + + -- Jihoon Kim Wed, 05 Jan 2011 08:44:58 +0900 + +ecore (1.0.0.001+svn.55755slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r55755 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55755slp2+build01 + + -- Jaehwan Kim Mon, 03 Jan 2011 21:19:00 +0900 + +ecore (1.0.0.001+svn.55594slp2+build02) unstable; urgency=low + + * Bug patch - ecore_x_xregion_is_empty() + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55594slp2+build02 + + -- Doyoun Kang Mon, 03 Jan 2011 12:56:39 +0900 + +ecore (1.0.0.001+svn.55594slp2+build01) unstable; urgency=low + + * [SVN EFL Migration] ecore in SLP is merged with SVN r55594 + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55594slp2+build01 + + -- Jaehwan Kim Wed, 22 Dec 2010 20:01:47 +0900 + +ecore (1.0.0.001+svn.55371slp2+build02) unstable; urgency=low + + * epoll disabled. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55371slp2+build02 + + -- WooHyun Jung Wed, 15 Dec 2010 16:37:29 +0900 + +ecore (1.0.0.001+svn.55371slp2+build01) unstable; urgency=low + + * [SVN's EFL Migration] ecore in SLP is merged with SVN r55371. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55371slp2+build01 + + -- Juyung Seo Tue, 14 Dec 2010 17:50:20 +0900 + +ecore (1.0.0.001+svn.55079slp2+build03) unstable; urgency=low + + * [SVN's EFL Migration] ecore in SLP is merged with SVN r55371. + * Git: 165.213.180.234:slp/pkgs/e/ecore + * Tag: ecore_1.0.0.001+svn.55079slp2+build03 + + -- Juyung Seo Tue, 14 Dec 2010 14:54:04 +0900 + +ecore (1.0.0.001+svn.55079slp2+build02) unstable; urgency=low + + * remove epoll + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.55079slp2+build02 + + -- Jaehwan Kim Thu, 02 Dec 2010 17:28:23 +0900 + +ecore (1.0.0.001+svn.55079slp2+build01) unstable; urgency=low + + * [SVN 55079 Merge] + * Update to SVN Revision 55079. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.55079slp2+build01 + + -- Myoungwoon Kim Thu, 02 Dec 2010 09:18:09 +0900 + +ecore (1.0.0.001+svn.51480slp2+build28) unstable; urgency=low + + * [ecore_evas] Patch code for rotation. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build28 + + -- Doyoun Kang Mon, 29 Nov 2010 10:14:56 +0900 + +ecore (1.0.0.001+svn.51480slp2+build27) unstable; urgency=low + + * [ecore_evas.c] change FPS rate print it every 0.1 sec + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build27 + + -- Seokjae Jeong Sat, 27 Nov 2010 15:06:21 +0900 + +ecore (1.0.0.001+svn.51480slp2+build26) unstable; urgency=low + + * [ecore_imf] remove unused typedefs + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build26 + + -- Jihoon Kim Fri, 26 Nov 2010 17:56:05 +0900 + +ecore (1.0.0.001+svn.51480slp2+build25) unstable; urgency=low + + * [SVN 54830 Merge] + * Update to SVN Revision 54830. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build25 + + -- Juyung Seo Fri, 26 Nov 2010 15:31:53 +0900 + +ecore (1.0.0.001+svn.51480slp2+build19) unstable; urgency=low + + * libcurl-dev -> libcurl4-openssl-dev + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build19 + + -- ChunEon Park Thu, 18 Nov 2010 21:26:21 +0900 + +ecore (1.0.0.001+svn.51480slp2+build18) unstable; urgency=low + + * [ecore_x] Add feature for sliding window + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build18 + + -- Doyoun Kang Thu, 11 Nov 2010 10:53:35 +0900 + +ecore (1.0.0.001+svn.51480slp2+build17) unstable; urgency=low + + * [ecore_imf] ecore_imf_context_input_panel_language_set + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build17 + + -- Jihoon Kim Tue, 09 Nov 2010 15:08:12 +0900 + +ecore (1.0.0.001+svn.51480slp2+build16) unstable; urgency=low + + * fix documentation of ecore_imf + * [src/lib/ecore_evas/Ecore_Evas.h] svn merge v51740. + * [svn merge] r51678~r51707 + * [svn merge] Changeset 51650 - Revert and reapply badnull patch + * [ecore_evas] svn 51618 : Add UNUSED where missing. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build16 + + -- Jihoon Kim Wed, 13 Oct 2010 16:54:37 +0900 + +ecore (1.0.0.001+svn.51480slp2+build15) unstable; urgency=low + + * fixed epoll + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build15 + + -- ChunEon Park Tue, 05 Oct 2010 10:39:49 +0900 + +ecore (1.0.0.001+svn.51480slp2+build14) unstable; urgency=low + + * [ecore_x_events.c] fixed double / triple click + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build14 + + -- ChunEon Park Mon, 04 Oct 2010 21:38:13 +0900 + +ecore (1.0.0.001+svn.51480slp2+build13) unstable; urgency=low + + * [ecore_evas] add EFL window rotation effect + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build13 + + -- Gwanglim Lee Sat, 02 Oct 2010 03:37:56 +0900 + +ecore (1.0.0.001+svn.51480slp2+build12) unstable; urgency=low + + * [ecore_imf] svn merge 52773 + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build12 + + -- Jihoon Kim Wed, 30 Sep 2010 09:56:30 +0900 + +ecore (1.0.0.001+svn.51480slp2+build10) unstable; urgency=low + + * update x_selection from upstream + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build10 + + -- Hyoyoung Chang Mon, 27 Sep 2010 17:27:38 +0900 + +ecore (1.0.0.001+svn.51480slp2+build09) unstable; urgency=low + + * repackaging + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build09 + + -- ChunEon Park Mon, 20 Sep 2010 21:42:20 +0900 + +ecore (1.0.0.001+svn.51480slp2+build08) unstable; urgency=low + + * Add ecore_imf_context_input_panel_caps_mode_set + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build08 + + -- Jihoon Kim Fri, 17 Sep 2010 15:48:17 +0900 + +ecore (1.0.0.001+svn.51480slp2+build07) unstable; urgency=low + + * Repackage for epoll disable + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build07 + + -- Hyoyoung Chang Fri, 17 Sep 2010 12:03:07 +0900 + +ecore (1.0.0.001+svn.51480slp2+build06) unstable; urgency=low + + * Repackage for epoll disable + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build06 + + -- WooHyun Jung Wed, 15 Sep 2010 18:15:43 +0900 + +ecore (1.0.0.001+svn.51480slp2+build05) unstable; urgency=low + + * Repackage for epoll disable + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build05 + + -- WooHyun Jung Wed, 15 Sep 2010 11:39:28 +0900 + +ecore (1.0.0.001+svn.51480slp2+build04) unstable; urgency=low + + * add as-needed + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build04 + + -- Jaehwan Kim Wed, 15 Sep 2010 10:00:16 +0900 + +ecore (1.0.0.001+svn.51480slp2+build03) unstable; urgency=low + + * repackage for stopping EPOLL fucntionality + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build03 + + -- WooHyun Jung Tue, 14 Sep 2010 16:05:25 +0900 + +ecore (1.0.0.001+svn.51480slp2+build02) unstable; urgency=low + + * repackage + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build02 + + -- Jaehwan Kim Fri, 10 Sep 2010 22:38:46 +0900 + +ecore (1.0.0.001+svn.51480slp2+build01) unstable; urgency=low + + * [ecore] Merge slp with SVN + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_1.0.0.001+svn.51480slp2+build01 + + -- Jaehwan Kim Wed, 01 Sep 2010 10:31:12 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build15) unstable; urgency=low + + * [rules] add disable-xim (from Wonkuk Jung) + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build15 + + -- Juyung Seo Wed, 01 Sep 2010 21:52:08 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build14) unstable; urgency=low + + * [ecore_x] fix sync issue in 1 special event re-order case. ( Changeset r51609 ) + * Reference : http://trac.enlightenment.org/e/changeset/51609 + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build14 + + -- Gwan-gyeong Mun Mon, 30 Aug 2010 08:46:33 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build13) unstable; urgency=low + + * [ecore_imf] add MONTH, NUMBERONLY Layout + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build13 + + -- Jihoon Kim Fri, 20 Aug 2010 11:23:12 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build12) unstable; urgency=low + + * [ecore_imf] change parameter type of event_callback_add + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build12 + + -- Jihoon Kim Fri, 30 Jul 2010 14:57:28 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build11) unstable; urgency=low + + * [ecore_imf] fix memory leak when private key or disable key func is used + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build11 + + -- Jihoon Kim Fri, 30 Jul 2010 14:32:07 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build10) unstable; urgency=low + + * Remove deprecated Ecore_IMF APIs. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build10 + + -- Jihoon Kim Tue, 20 Jul 2010 18:17:00 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build09) unstable; urgency=low + + * Repackage for beat release. + * Git: 165.213.180.234:/git/slp/pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build09 + + -- WooHyun Jung Mon, 19 Jul 2010 10:47:44 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build08) unstable; urgency=low + + * add the ECORE_X_ATOM_PARENT_BORDER_WINDOW atom. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build08 + + -- Gwanglim Lee Wed, 14 Jul 2010 15:41:35 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build07) unstable; urgency=low + + * Ecore_IMF API is revised. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build07 + + -- Jihoon Kim Thu, 08 Jul 2010 17:14:29 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build06) unstable; urgency=low + + * add ecore_evas_gl_x11_no_swap_set for supporting lock/unlock feature. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build06 + + -- ChunEon Park Wed, 07 Jul 2010 20:03:15 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build05) unstable; urgency=low + + * add ecore_evas_gl_x11_no_swap_set for supporting lock/unlock feature. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build05 + + -- Gwanglim Lee Tue, 29 Jun 2010 18:58:38 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build04) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build04 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 21:09:25 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build03) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build03 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 21:04:09 +0900 + +ecore (0.9.9.060+svn.49540slp2+3build02) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3build02 + + -- Daniel Juyung Seo 목, 10 6월 2010 21:00:51 +0900 + +ecore (0.9.9.060+svn.49540slp2+3) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+3 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 20:46:54 +0900 + +ecore (0.9.9.060+svn.49540slp2+2) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+2 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 20:46:08 +0900 + +ecore (0.9.9.060+svn.49540slp2+1) unstable; urgency=low + + * Packaging. + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL-pkgs/ecore + * Tag: ecore_0.9.9.060+svn.49540slp2+1 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 20:45:22 +0900 + +ecore (0.9.9.060+svn.49540slp2+0) unstable; urgency=low + + * Update opensource EFL from SVN + * SVN revision: 49540 (Total EFL revision: 49550) + * Tag: 0.9.9.060+svn.49540slp2+0 + + -- Daniel Juyung Seo Thu, 10 Jun 2010 15:50:38 +0900 + +ecore (0.9.9.060+svn20100304slp2+4) unstable; urgency=low + + * Enable curl + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL + * Tag: ecore_0.9.9.060+svn20100304slp2+4 + + -- Sangjin Lee Wed, 14 Apr 2010 17:54:37 +0900 + +ecore (0.9.9.060+svn20100304slp2+3) unstable; urgency=low + + * change control - add libeina-svn-04 dependency to libecore-svn-01 + * Git: 165.213.180.234:/git/slp2.0/slp2.0-pkgs/EFL + * Tag: 9.9.060+svn20100304slp2+3 + + -- Jaehwan Kim Thu, 01 Apr 2010 16:50:07 +0900 + +ecore (0.9.9.060+svn20100304slp2+2) unstable; urgency=low + + * add document in ecore_imf and cleanup + + -- Jihoon Kim Tue, 30 Mar 2010 16:55:51 +0900 + +ecore (0.9.9.060+svn20100304slp2+1) unstable; urgency=low + + * change package version + + -- Jaehwan Kim Thu, 25 Mar 2010 15:05:10 +0900 + +ecore (0.9.9.060+svn20100304-5) unstable; urgency=low + + * Upgrade ecore to 47360 + + -- Sangjin Lee Mon, 22 Mar 2010 20:52:51 +0900 + +ecore (0.9.9.060+svn20100304-4) unstable; urgency=low + + * Modifed keydefs.h for resolving macro name conflicts + + -- Ji-hoon Lee Mon, 22 Mar 2010 16:03:48 +0900 + +ecore (0.9.9.060+svn20100304-3) unstable; urgency=low + + * Added keydefs.h for identifying key index + + -- Ji-hoon Lee Fri, 19 Mar 2010 20:20:43 +0900 + +ecore (0.9.9.060+svn20100304-2) unstable; urgency=low + + * Fix debian/libecore-dev.install not to omit symbolic links for shared objects + + -- Sung-Jin Park Tue, 16 Mar 2010 21:26:16 +0900 + +ecore (0.9.9.060+svn20100304-1) unstable; urgency=low + + * EFL_update_revision_46864 + + -- Jaehwan Kim Thu, 11 Mar 2010 10:50:35 +0900 + +ecore (0.9.9.060+svn20100203-16) unstable; urgency=low + + * Modify shape input mask + + -- Sangjin Lee Thu, 11 Mar 2010 10:42:52 +0900 + +ecore (0.9.9.060+svn20100203-15) unstable; urgency=low + + * Modify ecore_x_window_hide(). + + In order to avoid ISE lockup problem, we ensure that root window + receives UnmapNotify event. + + -- Gwanglim Lee Wed, 10 Mar 2010 17:07:18 +0900 + +ecore (0.9.9.060+svn20100203-14) unstable; urgency=low + + * Merge source (based on SVN rev.46421). + * Add ecore_data library. + + -- Doyoun Kang Thu, 04 Mar 2010 20:17:30 +0900 + +ecore (0.9.9.060+svn20100203-13) unstable; urgency=low + + * Rollback to source (0.9.9.060+svn20100203-10) + + -- Doyoun Kang Thu, 04 Mar 2010 14:26:58 +0900 + +ecore (0.9.9.060+svn20100203-12) unstable; urgency=low + + * Merge the latest ecore_imf + + -- Jihoon Kim Thu, 04 Mar 2010 13:21:57 +0900 + +ecore (0.9.9.060+svn20100203-11) unstable; urgency=low + + * Merge source (based on SVN rev.46421) + + -- Doyoun Kang Thu, 04 Mar 2010 12:17:19 +0900 + +ecore (0.9.9.060+svn20100203-10) unstable; urgency=low + + * Add ecore_imf_context_ise_event_callback_set API. ise_state_add_listener, remove_listener, change_listener will be deprecated. + + -- Jihoon Kim Tue, 02 Mar 2010 17:52:58 +0900 + +ecore (0.9.9.060+svn20100203-9) unstable; urgency=low + + * Patch for ecore_evas_x_alpha_set + + -- Sangjin Lee Sat, 27 Feb 2010 20:44:34 +0900 + +ecore (0.9.9.060+svn20100203-8) unstable; urgency=low + + * add more ISE_EVENT types + + -- Jihoon Kim Thu, 25 Feb 2010 17:09:28 +0900 + +ecore (0.9.9.060+svn20100203-7) unstable; urgency=low + + * add ecore_imf_context_ise_get_window_rect API + + -- Jihoon Kim Tue, 23 Feb 2010 20:42:39 +0900 + +ecore (0.9.9.060+svn20100203-6) unstable; urgency=low + + * revision update to 46263. (partial merge) + * add atoms for rotation. + + -- Doyoun Kang Thu, 18 Feb 2010 19:37:45 +0900 + +ecore (0.9.9.060+svn20100203-5) unstable; urgency=low + + * elm_win_transparent apply + + -- Jaehwan Kim Thu, 11 Feb 2010 15:12:01 +0900 + +ecore (0.9.9.060+svn20100203-4) unstable; urgency=low + + * Add rotate with resize. + + -- Doyoun Kang Mon, 08 Feb 2010 14:14:00 +0900 + +ecore (0.9.9.060+svn20100203-3) unstable; urgency=low + + * repack + + -- sangho park Thu, 04 Feb 2010 22:04:12 +0900 + +ecore (0.9.9.060+svn20100203-2) unstable; urgency=low + + * repack + + -- Jaehwan Kim Thu, 04 Feb 2010 20:27:43 +0900 + +ecore (0.9.9.060+svn20100203-1) unstable; urgency=low + + * EFL_update_revision_45828 + + -- Jaehwan Kim Wed, 03 Feb 2010 16:39:21 +0900 + +ecore (0.9.9.060+svn20100119-2) unstable; urgency=low + + * updated ISF files + + -- sehwan Thu, 21 Jan 2010 23:23:29 +0900 + +ecore (0.9.9.060+svn20100119-1) unstable; urgency=low + + * EFL_update_revision_45322 + + -- Jihoon Kim Tue, 19 Jan 2010 20:44:48 +0900 + +ecore (0.9.9.060+svn20100111-4) unstable; urgency=low + + * changed ecore-imf for isf + + -- sehwan Fri, 15 Jan 2010 15:06:31 +0900 + +ecore (0.9.9.060+svn20100111-3) unstable; urgency=low + + * reupload EFL i686 + + -- Jaehwan Kim Tue, 12 Jan 2010 17:35:33 +0900 + +ecore (0.9.9.060+svn20100111-2) unstable; urgency=low + + * reupload EFL + + -- Jaehwan Kim Mon, 11 Jan 2010 22:16:49 +0900 + +ecore (0.9.9.060+svn20100111-1) unstable; urgency=low + + * update EFL revision 45026 + + -- Jaehwan Kim Mon, 11 Jan 2010 13:28:04 +0900 + +ecore (0.9.9.060+svn20091229-3) unstable; urgency=low + + * To solve version mismatch between i386 and armel. + * No source code changed. + + -- Jongwoo Chae Thu, 07 Jan 2010 21:47:34 +0900 + +ecore (0.9.9.060+svn20091229-2) unstable; urgency=low + + * Changed ecore_imf for isf package + + -- Ji-hoon Lee Wed, 06 Jan 2010 13:55:00 +0900 + +ecore (0.9.9.060+svn20091229-1) unstable; urgency=low + + * update EFL + + -- Jaehwan Kim Tue, 29 Dec 2009 14:27:03 +0900 + +ecore (0.9.9.060+svn20091112-6) unstable; urgency=low + + * modified debian/control to link libcurl + + -- Jihoon Kim Tue, 29 Dec 2009 19:31:19 +0900 + + +ecore (0.9.9.060+svn20091112-5) unstable; urgency=low + + * modified debian/control : changed Architecture all to any (by Juyung Seo) + + -- Sangho Park Fri, 27 Nov 2009 15:59:07 +0900 + +ecore (0.9.9.060+svn20091112-4) unstable; urgency=low + + * svn stable version + + -- Sangho Park Thu, 19 Nov 2009 18:50:08 +0900 + +ecore (0.9.9.060+svn20091112-3) unstable; urgency=low + + * add build dependency glib + + -- Sangho Park Tue, 17 Nov 2009 21:37:23 +0900 + +ecore (0.9.9.060+svn20091112-2) unstable; urgency=low + + * add glib dependency + + -- Sangho Park Tue, 17 Nov 2009 16:27:18 +0900 + +ecore (0.9.9.060+svn20091112-1) unstable; urgency=low + + * New version + + -- Sangho Park Thu, 12 Nov 2009 23:44:06 +0900 + +ecore (0.9.9.060+svnYYYYMMDD-1) unstable; urgency=low + + * New version + + -- quaker Thu, 22 Apr 2009 18:12:06 +0100 + +ecore (0.9.9.050+svnYYYYMMDD-1) unstable; urgency=low + + * Clean up changelog + + -- quaker Tue, 21 Apr 2009 19:14:37 +0100 diff --git a/debian/compat b/debian/compat index 1e8b314..7ed6ff8 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -6 +5 diff --git a/debian/control b/debian/control old mode 100644 new mode 100755 index d1e0b78..7e8abae --- a/debian/control +++ b/debian/control @@ -1,27 +1,62 @@ Source: ecore Section: libs Priority: optional -Maintainer: Falko Schmidt -Build-Depends: debhelper (>= 6), cdbs, libeet-dev, libevas-dev, libssl-dev, libcurl4-openssl-dev, libxcursor-dev, libxss-dev, libxrender-dev, libxinerama-dev, libxrandr-dev, libxext-dev, libxp-dev, libxcomposite-dev, libjpeg62-dev, libxdamage-dev, doxygen -Standards-Version: 3.7.3 -Homepage: http://www.enlightenment.org +Maintainer: Jaehwan Kim , + Jihoon Kim , + Sangjin Lee , + Doyoun Kang , + Sung-Jin Park , + Juyung Seo , + Seokjae Jeong , + ChunEon Park , + WooHyun Jung , + Gwanglim Lee , + Ji-hoon Lee , + Gwan-gyeong Mun , + Hyoyoung Chang , + Myoungwoon Kim , + Seokjae Jeong , + Mike McCormack , + Jeonghyun Yun +Uploaders: Tae-Hwan Kim +Build-Depends: dpkg-dev, + debhelper (>= 6), + cdbs, + libeina-dev (>= 0.0.2.060+svn20100304), + libeet-dev (>= 1.0.0), + libxgesture-dev, + libevas-dev , + libglib2.0-dev, + libxcursor-dev, + libxrender-dev, + libxinerama-dev, + libxrandr-dev, + libxext-dev, + libxcomposite-dev, + libjpeg8-dev, + libxdamage-dev, + x11proto-xext-dev, + libxtst-dev, + doxygen, + pkg-config, + libtool, + libcurl-dev, +Standards-Version: 3.8.1 +Homepage: http://enlightenment.org -Package: libecore0 +Package: libecore Architecture: any -Provides: libecore -Depends: ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, libeina Description: Core abstraction layer for enlightenment DR 0.17 This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and 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: libecore-con0 + +Package: libecore-con Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-con +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore Connection Library This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -30,12 +65,10 @@ Description: Ecore Connection Library applications. . This package contains the Ecore Connection Library. - -Package: libecore-config0 + +Package: libecore-config Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-config +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore Enlightened Property Library This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -44,12 +77,10 @@ Description: Ecore Enlightened Property Library applications. . This package contains the Enlightened Property Library. - -Package: libecore-evas0 + +Package: libecore-evas Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-evas +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore Evas Wrapper Library This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -58,12 +89,10 @@ Description: Ecore Evas Wrapper Library applications. . This package contains the Ecore Evas wrapper functions. - -Package: libecore-fb0 + +Package: libecore-fb Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-fb +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore frame buffer system functions This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -72,12 +101,10 @@ Description: Ecore frame buffer system functions applications. . This package contains the Ecore frame buffer system functions. - -Package: libecore-file0 + +Package: libecore-file Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-file +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore File Library This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -86,41 +113,35 @@ Description: Ecore File Library applications. . This package contains the Ecore File Library. - -Package: libecore-imf0 + +Package: libecore-imf Architecture: any -Section: libs -Depends: ${shlibs:Depends}, libecore-imf-evas0 -Provides: libecore-imf -Description: Ecore Input Method Framework module +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Ecore Input Method Framework module This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and 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. . - This package contains the Ecore Input Method Framework module. - -Package: libecore-imf-evas0 + This package contains the Ecore Input Method Framework module, and the Evas + helper functions for it. + +Package: libecore-input Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-imf-evas -Description: Evas helpers for the Ecore Input Method Framework +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: Ecore input functions This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and 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. . - This package contains the Evas helper functions for the Ecore Input Method - Framework module. - -Package: libecore-ipc0 + This package contains the Ecore Input Library. + +Package: libecore-ipc Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-ipc +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore inter-process communication functions This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -129,40 +150,15 @@ Description: Ecore inter-process communication functions applications. . This package contains the Ecore inter-process communication functions. - -Package: libecore-job0 -Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-job -Description: Ecore job dealing functions - This is the core event abstraction layer and X abstraction layer that makes - doing selections, Xdnd, general X stuff, and 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. - . - This package contains functions for dealing with Ecore jobs. - -Package: libecore-txt0 + +Package: libecore-data Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-txt -Description: Ecore text encoding conversion functions - This is the core event abstraction layer and X abstraction layer that makes - doing selections, Xdnd, general X stuff, and 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. - . - This package contains the Ecore text encoding conversion functions. - -Package: libecore-x0 +Depends: ${misc:Depends} +Description: Ecore data functions + +Package: libecore-x Architecture: any -Section: libs -Depends: ${shlibs:Depends} -Provides: libecore-x +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Ecore functions for dealing with the X Windows System This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -172,40 +168,26 @@ Description: Ecore functions for dealing with the X Windows System . This package contains the Ecore wrapper and convenience functions for using the X Windows System. - -Package: libecore0-all -Architecture: any -Section: libdevel -Depends: libecore0 (= ${Source-Version}), libecore-config0, libecore-con0, libecore-evas0, libecore-fb0, libecore-file0, libecore-imf0, libecore-ipc0, libecore-job0, libecore-txt0, libecore-x0 -Provides: libecore-all -Description: Virtual package providing all available Ecore modules. - This is the core event abstraction layer and X abstraction layer that makes - doing selections, Xdnd, general X stuff, and 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. - . - This virtual package provides all available Ecore modules. Package: libecore-dev Architecture: any Section: libdevel Suggests: libecore-doc -Depends: libecore0 (= ${binary:Version}), - libecore-con0 (= ${binary:Version}), - libecore-config0 (= ${binary:Version}), - libecore-evas0 (= ${binary:Version}), - libecore-fb0 (= ${binary:Version}), - libecore-file0 (= ${binary:Version}), - libecore-imf0 (= ${binary:Version}), - libecore-ipc0 (= ${binary:Version}), - libecore-job0 (= ${binary:Version}), - libecore-txt0 (= ${binary:Version}), - libecore-x0 (= ${binary:Version}), - libeet-dev, libevas-dev, pkg-config, - libssl-dev, libcurl4-openssl-dev, libxcursor-dev, libxss-dev, - libxrender-dev, libxinerama-dev, libxrandr-dev, libxext-dev, - libxp-dev, libxcomposite-dev, libxdamage-dev +Depends: ${misc:Depends}, libecore (= ${binary:Version}), + libecore-con (= ${binary:Version}), + libecore-config (= ${binary:Version}), + libecore-evas (= ${binary:Version}), + libecore-fb (= ${binary:Version}), + libecore-file (= ${binary:Version}), + libecore-imf (= ${binary:Version}), + libecore-input (= ${binary:Version}), + libecore-ipc (= ${binary:Version}), + libecore-x (= ${binary:Version}), + libecore-data (= ${binary:Version}), + libxgesture-dev, + libeet-dev, libevas-dev (>= 0.9.9.060), libeina-dev, pkg-config, libcurl-dev, + libxcursor-dev, libxrender-dev, libxinerama-dev, libxrandr-dev, libxext-dev, + libxcomposite-dev, libxdamage-dev, x11proto-xext-dev, libxtst-dev, libglib2.0-dev Description: Ecore headers and static libraries This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -216,8 +198,9 @@ Description: Ecore headers and static libraries This package contains headers and static libraries for the Ecore library. Package: libecore-doc -Architecture: all +Architecture: any Section: doc +Depends: ${misc:Depends} Enhances: libecore-dev Description: Ecore API Documentation This is the core event abstraction layer and X abstraction layer that makes @@ -232,7 +215,7 @@ Description: Ecore API Documentation Package: libecore-bin Architecture: any Section: utils -Depends: ${shlibs:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends} Description: Tools that support Ecore This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle @@ -247,8 +230,8 @@ Package: libecore-dbg Architecture: any Section: libdevel Priority: extra -Depends: libecore0 (= ${binary:Version}) -Description: Core abstraction layer for enlightenment DR 0.17 +Depends: ${misc:Depends}, libecore (= ${binary:Version}) +Description: Debugging symbols for libecore This is the core event abstraction layer and X abstraction layer that makes doing selections, Xdnd, general X stuff, and event loops, timeouts and idle handlers fast, optimized, and convenient. It's a separate library so anyone diff --git a/debian/copyright b/debian/copyright index d086d3b..57d5703 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,18 +1,24 @@ -This package was debianized by Falko Schmidt on -Fri, 4 Apr 2008 15:13:56 +0000. +This package was debianized by Debian Pkg-e Team +Sat, 07 Jul 2007 09:29:10 +0000. -The source code is from the e17/libs/ecore module of the enlightenment CVS -tree. For more information, see: +It was downloaded from http://download.enlightenment.org/ - http://www.enlightenment.org - Upstream Authors: - + Enlightenment team Copyright: - Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + + Additional Copyright: + src/lib/ecore/ecore_str.c: Copyright (c) 1998 Todd C. Miller + + src/lib/ecore/ecore_value.c: Copyright (C) 2001 + Christopher Rosendahl + Nathan Ingersoll + src/lib/ecore_fb/ecore_fb_li.c: Copyright (C) 1999-2002 Brad Hards + License: Permission is hereby granted, free of charge, to any person obtaining a @@ -36,7 +42,3 @@ License: On Debian systems, the complete text of the BSD License can be found in `/usr/share/common-licenses/BSD'. - -The Debian packaging is: - (C) 2006 2007,Debian Pkg-e Team - and is licensed under the GPL, see `/usr/share/common-licenses/GPL'. diff --git a/debian/jobs b/debian/jobs new file mode 100644 index 0000000..e69de29 diff --git a/debian/libecore-bin.install b/debian/libecore-bin.install index 088dd41..24d1f12 100644 --- a/debian/libecore-bin.install +++ b/debian/libecore-bin.install @@ -1 +1 @@ -debian/tmp/usr/bin/ecore_config +#debian/tmp/usr/bin/ecore_config diff --git a/debian/libecore-con-svn-01.install b/debian/libecore-con-svn-01.install new file mode 100644 index 0000000..4e6f99e --- /dev/null +++ b/debian/libecore-con-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_con-*.so.* diff --git a/debian/libecore-con-svn-01.shlibs b/debian/libecore-con-svn-01.shlibs new file mode 100644 index 0000000..d5353f3 --- /dev/null +++ b/debian/libecore-con-svn-01.shlibs @@ -0,0 +1 @@ +libecore_con-ver-pre-svn-01 0 libecore-con-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-con.install b/debian/libecore-con.install new file mode 100644 index 0000000..1c47c56 --- /dev/null +++ b/debian/libecore-con.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_con.so.* diff --git a/debian/libecore-config-svn-01.install b/debian/libecore-config-svn-01.install new file mode 100644 index 0000000..d497998 --- /dev/null +++ b/debian/libecore-config-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_config-*.so.* diff --git a/debian/libecore-config-svn-01.shlibs b/debian/libecore-config-svn-01.shlibs new file mode 100644 index 0000000..ec0e971 --- /dev/null +++ b/debian/libecore-config-svn-01.shlibs @@ -0,0 +1 @@ +libecore_config-ver-pre-svn-01 0 libecore-config-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-config.install b/debian/libecore-config.install new file mode 100644 index 0000000..8f31d99 --- /dev/null +++ b/debian/libecore-config.install @@ -0,0 +1 @@ +#debian/tmp/usr/lib/libecore_config.so.* diff --git a/debian/libecore-dev.install b/debian/libecore-dev.install old mode 100644 new mode 100755 index 497be28..e6def58 --- a/debian/libecore-dev.install +++ b/debian/libecore-dev.install @@ -1,4 +1,14 @@ -debian/tmp/usr/include/*.h +debian/tmp/usr/include/ecore-1/Ecore*.h debian/tmp/usr/lib/libecore*.a +debian/tmp/usr/lib/libecore*.la debian/tmp/usr/lib/libecore*.so -debian/tmp/usr/lib/pkgconfig/* +#debian/tmp/usr/lib/libecore_config*.so +debian/tmp/usr/lib/libecore_con*.so +debian/tmp/usr/lib/libecore_evas*.so +debian/tmp/usr/lib/libecore_file*.so +debian/tmp/usr/lib/libecore_imf_evas*.so +debian/tmp/usr/lib/libecore_imf*.so +debian/tmp/usr/lib/libecore_input*.so +debian/tmp/usr/lib/libecore_ipc*.so +debian/tmp/usr/lib/libecore_x*.so +debian/tmp/usr/lib/pkgconfig/ecore*.pc diff --git a/debian/libecore-doc.doc-base b/debian/libecore-doc.doc-base new file mode 100644 index 0000000..9ab7e32 --- /dev/null +++ b/debian/libecore-doc.doc-base @@ -0,0 +1,10 @@ +Document: ecore +Title: Ecore Guide +Author: Carsten Haitzler +Abstract: This document describes Ecore API + and provides sample C code. +Section: Programming/C + +Format: HTML +Index: /usr/share/doc/libecore-doc/html/index.html +Files: /usr/share/doc/libecore-doc/html/*.html diff --git a/debian/libecore-evas-svn-01.install b/debian/libecore-evas-svn-01.install new file mode 100644 index 0000000..ceb9f01 --- /dev/null +++ b/debian/libecore-evas-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_evas-*.so.* diff --git a/debian/libecore-evas-svn-01.shlibs b/debian/libecore-evas-svn-01.shlibs new file mode 100644 index 0000000..92c2b6d --- /dev/null +++ b/debian/libecore-evas-svn-01.shlibs @@ -0,0 +1 @@ +libecore_evas-ver-pre-svn-01 0 libecore-evas-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-evas.install b/debian/libecore-evas.install new file mode 100644 index 0000000..12d49fb --- /dev/null +++ b/debian/libecore-evas.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_evas*.so.* diff --git a/debian/libecore-fb-svn-01.install b/debian/libecore-fb-svn-01.install new file mode 100644 index 0000000..72ceee2 --- /dev/null +++ b/debian/libecore-fb-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_fb-*.so.* diff --git a/debian/libecore-fb-svn-01.shlibs b/debian/libecore-fb-svn-01.shlibs new file mode 100644 index 0000000..2593f16 --- /dev/null +++ b/debian/libecore-fb-svn-01.shlibs @@ -0,0 +1 @@ +libecore_fb-ver-pre-svn-01 0 libecore-fb-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-fb.install b/debian/libecore-fb.install new file mode 100644 index 0000000..f228623 --- /dev/null +++ b/debian/libecore-fb.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_fb*.so.* diff --git a/debian/libecore-file-svn-01.install b/debian/libecore-file-svn-01.install new file mode 100644 index 0000000..a115a75 --- /dev/null +++ b/debian/libecore-file-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_file-*.so.* diff --git a/debian/libecore-file-svn-01.shlibs b/debian/libecore-file-svn-01.shlibs new file mode 100644 index 0000000..868a4f6 --- /dev/null +++ b/debian/libecore-file-svn-01.shlibs @@ -0,0 +1 @@ +libecore_file-ver-pre-svn-01 0 libecore-file-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-file.install b/debian/libecore-file.install new file mode 100644 index 0000000..74419ea --- /dev/null +++ b/debian/libecore-file.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_file*.so.* diff --git a/debian/libecore-imf-svn-01.install b/debian/libecore-imf-svn-01.install new file mode 100644 index 0000000..8da8885 --- /dev/null +++ b/debian/libecore-imf-svn-01.install @@ -0,0 +1,2 @@ +debian/tmp/usr/lib/libecore_imf-*.so.* +debian/tmp/usr/lib/libecore_imf_evas-*.so.* diff --git a/debian/libecore-imf-svn-01.shlibs b/debian/libecore-imf-svn-01.shlibs new file mode 100644 index 0000000..15aeb84 --- /dev/null +++ b/debian/libecore-imf-svn-01.shlibs @@ -0,0 +1,2 @@ +libecore_imf-ver-pre-svn-01 0 libecore-imf-svn-01 (>= 0.9.9.060+svnYYYYMMDD) +libecore_imf_evas-ver-pre-svn-01 0 libecore-imf-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-imf.install b/debian/libecore-imf.install new file mode 100644 index 0000000..88f91c5 --- /dev/null +++ b/debian/libecore-imf.install @@ -0,0 +1,2 @@ +debian/tmp/usr/lib/libecore_imf*.so.* +debian/tmp/usr/lib/libecore_imf_evas*.so.* diff --git a/debian/libecore-input-svn-01.install b/debian/libecore-input-svn-01.install new file mode 100644 index 0000000..34d8efb --- /dev/null +++ b/debian/libecore-input-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_input-*.so.* diff --git a/debian/libecore-input-svn-01.shlibs b/debian/libecore-input-svn-01.shlibs new file mode 100644 index 0000000..b95c6bb --- /dev/null +++ b/debian/libecore-input-svn-01.shlibs @@ -0,0 +1 @@ +libecore_input-ver-pre-svn-01 0 libecore-input-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-input.install b/debian/libecore-input.install new file mode 100644 index 0000000..4509237 --- /dev/null +++ b/debian/libecore-input.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_input*.so.* diff --git a/debian/libecore-ipc-svn-01.install b/debian/libecore-ipc-svn-01.install new file mode 100644 index 0000000..e118708 --- /dev/null +++ b/debian/libecore-ipc-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_ipc-*.so.* diff --git a/debian/libecore-ipc-svn-01.shlibs b/debian/libecore-ipc-svn-01.shlibs new file mode 100644 index 0000000..6a9ae5a --- /dev/null +++ b/debian/libecore-ipc-svn-01.shlibs @@ -0,0 +1 @@ +libecore_ipc-ver-pre-svn-01 0 libecore-ipc-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-ipc.install b/debian/libecore-ipc.install new file mode 100644 index 0000000..f0421a3 --- /dev/null +++ b/debian/libecore-ipc.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_ipc*.so.* diff --git a/debian/libecore-svn-01.install b/debian/libecore-svn-01.install new file mode 100644 index 0000000..22c55a3 --- /dev/null +++ b/debian/libecore-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore-*.so.* diff --git a/debian/libecore-svn-01.shlibs b/debian/libecore-svn-01.shlibs new file mode 100644 index 0000000..43565e1 --- /dev/null +++ b/debian/libecore-svn-01.shlibs @@ -0,0 +1 @@ +libecore-ver-pre-svn-01 0 libecore-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-x-svn-01.install b/debian/libecore-x-svn-01.install new file mode 100644 index 0000000..8c8007e --- /dev/null +++ b/debian/libecore-x-svn-01.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_x-*.so.* diff --git a/debian/libecore-x-svn-01.shlibs b/debian/libecore-x-svn-01.shlibs new file mode 100644 index 0000000..b5a9660 --- /dev/null +++ b/debian/libecore-x-svn-01.shlibs @@ -0,0 +1 @@ +libecore_x-ver-pre-svn-01 0 libecore-x-svn-01 (>= 0.9.9.060+svnYYYYMMDD) diff --git a/debian/libecore-x.install b/debian/libecore-x.install new file mode 100644 index 0000000..e098222 --- /dev/null +++ b/debian/libecore-x.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore_x*.so.* diff --git a/debian/libecore.install b/debian/libecore.install new file mode 100644 index 0000000..7eef82a --- /dev/null +++ b/debian/libecore.install @@ -0,0 +1 @@ +debian/tmp/usr/lib/libecore.so.* diff --git a/debian/rules b/debian/rules old mode 100644 new mode 100755 index 3d51bbb..494fe33 --- a/debian/rules +++ b/debian/rules @@ -3,26 +3,41 @@ include /usr/share/cdbs/1/class/autotools.mk include /usr/share/cdbs/1/rules/debhelper.mk -#DEB_INSTALL_MANPAGES_libecore-doc := $(DEB_SRCDIR)/doc/man/man3/*.3 -DEB_INSTALL_MANPAGES_libecore-bin := debian/ecore_config.1 +DEB_CONFIGURE_SCRIPT := ./autogen.sh +#DEB_INSTALL_MANPAGES_libecore-bin := debian/ecore_config.1 DEB_DH_STRIP_ARGS := --dbg-package=libecore-dbg -DEB_CONFIGURE_EXTRA_FLAGS := --enable-ecore-fb --disable-ecore-directfb \ - --disable-ecore-evas-dfb --enable-ecore-evas-fb --disable-rpath \ - --enable-openssl -DEB_MAKE_CLEAN_TARGET := clean +DEB_CONFIGURE_EXTRA_FLAGS := --enable-ecore-fb \ + --enable-dependency-tracking \ + --disable-ecore-directfb \ + --enable-ecore-evas-fb \ + --disable-rpath \ + --disable-openssl \ + --disable-gnutls \ + --disable-tslib \ + --disable-doc \ + --enable-simple-x11 \ + --enable-ecore-evas-opengl-x11 \ + --disable-ecore-evas-xrender-x11 \ + --enable-curl \ + --disable-openssl \ + --enable-glib-integration-always \ + --enable-ecore-x-gesture \ + --disable-xim \ + --disable-ecore-imf-xim \ + --disable-ecore-imf-scim +DEB_MAKE_EXTRA_ARGS := V=0 -build/libecore-doc:: - cd $(DEB_SRCDIR) && doxygen +DEB_MAKE_CLEAN_TARGET := distclean +CFLAGS += -fvisibility=hidden -fPIC +LDFLAGS += -fvisibility=hidden -Wl,--hash-style=both -Wl,--as-needed -install/libecore-doc:: - mkdir -p debian/libecore-doc/usr/share/doc/libecore-doc/ - cp -R $(DEB_SRCDIR)/doc/html debian/libecore-doc/usr/share/doc/libecore-doc/ - cd $(DEB_SRCDIR)/doc/man/man3 && ls -1 | grep -vi ecore | xargs rm +#build/libecore-doc:: +# cd $(DEB_SRCDIR)/doc && make doc -clean:: - rm -rf $(DEB_SRCDIR)/doc/html $(DEB_SRCDIR)/doc/latex $(DEB_SRCDIR)/doc/man - mkdir -p $(DEB_SRCDIR)/doc/html - cp $(DEB_SRCDIR)/doc/img/*.png $(DEB_SRCDIR)/doc/html/ - cp $(DEB_SRCDIR)/doc/img/*.gif $(DEB_SRCDIR)/doc/html/ - ./autogen.sh --prefix=/usr $(DEB_CONFIGURE_EXTRA_FLAGS) +#install/libecore-doc:: +# mkdir -p debian/libecore-doc/usr/share/doc/libecore-doc +# cp -R $(DEB_SRCDIR)/doc/html debian/libecore-doc/usr/share/doc/libecore-doc/ +clean:: + [ ! -f Makefile ] || make distclean + rm -f ecore-*.tar.bz2 ecore-*.tar.bz2.cdbs-config_list 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 index 604ee7f..2dd6b44 100644 --- a/doc/e.css +++ b/doc/e.css @@ -1,161 +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 { - background: url("b.png"); - background-repeat: repeat-x; - background-position: top left; - background-color: #f4f4f4; - text-align: center; - font-family: sans-serif; - padding: 0; - margin: 0; -} - -div.main { - margin: 1em auto; - vertical-align: top; - font-family: "Bitstream Vera", "Vera", "Trebuchet MS", Trebuchet, Tahoma, sans-serif; - color: #444444; - font-size: 0.8em; - text-align: justify; - width: 80%; -} - -td.t { background-image:url("t.gif"); } -td.t[class] { background-image:url("t.png"); } -td.tl { background-image:url("tl.gif"); } -td.tl[class] { background-image:url("tl.png"); } - -td.nav, td.lnav, td.rnav { - align: middle; - text-align: center; - vertical-align: middle; - width: 100px; - height: 25px; - font-family: "Bitstream Vera", "Vera", "Trebuchet MS", Trebuchet, Tahoma, sans-serif; - color: #000000; - font-size: 9px; - font-weight: bold; - white-space: no-wrap; -} - -td.lnav[class] { background-image:url("n.png"); } -td.lnav[class] { background-image:url("n.png"); } -td.rnav { background-image:url("n.gif"); } -td.rnav[class] { background-image:url("n.png"); } - -hr { - width: 200px; - height: 1px; - background: #dddddd; - border: 0; -} - -p { color: #444444 ;} -p.tiny, small { - color: #888888; - font-size: 0.5em; -} - -h1 { - text-align: center; - font-size: 1.3em; -} - -h2 { font-size: 1.1em; } -h3 { font-size: 0.9em; } - -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; } - -a:link { - color: #445566; - text-decoration: underline; -} - -a:visited { - color: #667788; - text-decoration: underline; -} - -a:active { - color: #88cccc; - text-decoration: none; -} - -a:hover { - color: #112266; - text-decoration: underline; -} - -a.nav { - text-decoration: none; - display: block; -} - -a.nav:link, a.nav:visited { color: #888888; } -a.nav:active { color: #000000; } -a.nav:hover { color: #444444; } -a.code:link, a.code:visited { text-decoration: none; } - -div.fragment { - font-size: 1em; - border: 1px dotted #cccccc; - background-color: #ffffff; - text-align: left; - vertical-align: middle; - padding: 2px; - margin-left: 25px; - margin-right: 25px; - overflow: auto; -} - -td.indexkey { - font-weight: bold; - padding-left: 10px; - padding-right: 0; - padding-top: 2px; - padding-bottom: 0px; - margin: 0; - margin-top: 2px; - margin-bottom: 2px; - border: 1px dotted #cccccc; - border-right: 0px dotted #cccccc; -} - -td.indexvalue { - font-style: italic; - padding-right: 10px; - padding-left: 0; - padding-top: 2px; - padding-bottom: 2px; - margin: 0; - margin-top: 2px; - margin-bottom: 2px; - border: 1px dotted #cccccc; - border-left: 0px dotted #cccccc; -} - -.mdescRight { font-style: italic; } -.memitem { - padding-left: 2px; - padding-right: 2px; - border: 1px dotted #cccccc; - background-color: #ffffff; -} -.memname { - white-space: nowrap; - font-weight: bold; -} -.paramname { font-weight: normal; } - -div.ah { - border: thin solid #888888; - font-weight: bold; - margin-bottom: 3px; - margin-top: 3px; + /*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 index 0d3303d..a915831 100644 --- a/doc/foot.html +++ b/doc/foot.html @@ -1,6 +1,19 @@ + +
+ + + + + + + -
-

Copyright © Enlightenment.org

-

$projectname Documentation Generated: $datetime

- + + + diff --git a/doc/head.html b/doc/head.html index a68f72a..2c61795 100644 --- a/doc/head.html +++ b/doc/head.html @@ -1,46 +1,69 @@ - - - - $title - - + + $title + + + + + + + + + + + - - - - - - -
- - - - - -
Download
-
- - - - - - - - - - -
-
-
- - - - - -
Support
-
- -
+ +
+ + + +
+
diff --git a/doc/img/e.png b/doc/img/e.png new file mode 100644 index 0000000000000000000000000000000000000000..d42aeb420098578b19a3eab3d6d1e6e73e3277bc GIT binary patch literal 30052 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 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 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

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 index 06c89c1c1e3d431910d50a9a252b02576daba1ee..20892e3cbd40e2df6ad74f358f8fb21cf2e0aa74 100644 GIT binary patch literal 24099 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 z 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 diff --git a/ecore-cocoa.pc.in b/ecore-cocoa.pc.in new file mode 100644 index 0000000..91fc4ee --- /dev/null +++ b/ecore-cocoa.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-cocoa +Description: E core library, Cocoa module +@pkgconfig_requires_private@: @requirements_ecore_cocoa@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_cocoa +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-con.manifest b/ecore-con.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-con.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-con.pc.in b/ecore-con.pc.in index c0ad576..9b188aa 100644 --- a/ecore-con.pc.in +++ b/ecore-con.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-con Description: E core library, Con module -Requires: ecore @requirements_ecore_con@ +@pkgconfig_requires_private@: @requirements_ecore_con@ Version: @VERSION@ Libs: -L${libdir} -lecore_con -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-config.pc.in b/ecore-config.pc.in index 2d11077..0235eb8 100644 --- a/ecore-config.pc.in +++ b/ecore-config.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-config Description: E core library, Config module -Requires: ecore @requirements_ecore_config@ +@pkgconfig_requires_private@: @requirements_ecore_config@ Version: @VERSION@ Libs: -L${libdir} -lecore_config -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-directfb.pc.in b/ecore-directfb.pc.in index 4262972..9eb104a 100644 --- a/ecore-directfb.pc.in +++ b/ecore-directfb.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-directfb Description: E core library, DirectFB module -Requires: ecore @requirements_ecore_directfb@ +@pkgconfig_requires_private@: @requirements_ecore_directfb@ Version: @VERSION@ Libs: -L${libdir} -lecore_directfb -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-evas.manifest b/ecore-evas.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-evas.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-evas.pc.in b/ecore-evas.pc.in index 164b863..155abbe 100644 --- a/ecore-evas.pc.in +++ b/ecore-evas.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-evas Description: E core library, Evas module -Requires: ecore @requirements_ecore_evas@ +@pkgconfig_requires_private@: @requirements_ecore_evas@ Version: @VERSION@ -Libs: -L${libdir} -lecore_evas @ecore_evas_libs@ -Cflags: -I${includedir} +Libs: -L${libdir} @ecore_evas_libs@ +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-fb.manifest b/ecore-fb.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-fb.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-fb.pc.in b/ecore-fb.pc.in index 6402ce4..4e70c48 100644 --- a/ecore-fb.pc.in +++ b/ecore-fb.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-fb Description: E core library, FB module -Requires: ecore @requirements_ecore_fb@ +@pkgconfig_requires_private@: @requirements_ecore_fb@ Version: @VERSION@ Libs: -L${libdir} -lecore_fb -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-file.manifest b/ecore-file.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-file.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-file.pc.in b/ecore-file.pc.in index 2dde219..833ff1e 100644 --- a/ecore-file.pc.in +++ b/ecore-file.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-file Description: E core library, File module -Requires: ecore @requirements_ecore_file@ +@pkgconfig_requires_private@: @requirements_ecore_file@ Version: @VERSION@ Libs: -L${libdir} -lecore_file -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-imf-evas.manifest b/ecore-imf-evas.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-imf-evas.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-imf-evas.pc.in b/ecore-imf-evas.pc.in index 0ce11d5..23451c8 100644 --- a/ecore-imf-evas.pc.in +++ b/ecore-imf-evas.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-imf-evas Description: E core library, IMF Evas module -Requires: ecore-imf evas +@pkgconfig_requires_private@: @requirements_ecore_imf_evas@ Version: @VERSION@ Libs: -L${libdir} -lecore_imf_evas -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-imf.manifest b/ecore-imf.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-imf.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-imf.pc.in b/ecore-imf.pc.in index 7a98b8c..cc155ed 100644 --- a/ecore-imf.pc.in +++ b/ecore-imf.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-imf Description: E core library, IMF module -Requires: ecore +@pkgconfig_requires_private@: @requirements_ecore_imf@ Version: @VERSION@ Libs: -L${libdir} -lecore_imf -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-input-evas.manifest b/ecore-input-evas.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-input-evas.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-input-evas.pc.in b/ecore-input-evas.pc.in new file mode 100644 index 0000000..f95325c --- /dev/null +++ b/ecore-input-evas.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-input-evas +Description: E core library, Input module Evas extension +@pkgconfig_requires_private@: @requirements_ecore_input_evas@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_input_evas +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-input.manifest b/ecore-input.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-input.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-input.pc.in b/ecore-input.pc.in new file mode 100644 index 0000000..b670b71 --- /dev/null +++ b/ecore-input.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-input +Description: E core library, Input module +@pkgconfig_requires_private@: @requirements_ecore_input@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_input +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-ipc.manifest b/ecore-ipc.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-ipc.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-ipc.pc.in b/ecore-ipc.pc.in index 2dc4beb..d66f404 100644 --- a/ecore-ipc.pc.in +++ b/ecore-ipc.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-ipc Description: E core library, IPC module -Requires: ecore-con @requirements_ecore_ipc@ +@pkgconfig_requires_private@: @requirements_ecore_ipc@ Version: @VERSION@ Libs: -L${libdir} -lecore_ipc -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-psl1ght.pc.in b/ecore-psl1ght.pc.in new file mode 100644 index 0000000..e81f4e8 --- /dev/null +++ b/ecore-psl1ght.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-psl1ght +Description: E core library, PSL1GHT module +@pkgconfig_requires_private@: @requirements_ecore_psl1ght@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_psl1ght +Libs.private: -lio -lsysutil -lgem -lcamera -lspurs +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-sdl.pc.in b/ecore-sdl.pc.in index bba6f88..78170c1 100644 --- a/ecore-sdl.pc.in +++ b/ecore-sdl.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: ecore-sdl Description: E core library, SDL module -Requires: ecore @requirements_ecore_sdl@ +@pkgconfig_requires_private@: @requirements_ecore_sdl@ Version: @VERSION@ Libs: -L${libdir} -lecore_sdl -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-wayland.pc.in b/ecore-wayland.pc.in new file mode 100644 index 0000000..f4f5cf3 --- /dev/null +++ b/ecore-wayland.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ecore-wayland +Description: E core library, Wayland module +@pkgconfig_requires_private@: @requirements_ecore_wayland@ +Version: @VERSION@ +Libs: -L${libdir} -lecore_wayland +Libs.private: -lwayland-client +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-win32.pc.in b/ecore-win32.pc.in index 9d403ff..ac5ab32 100644 --- a/ecore-win32.pc.in +++ b/ecore-win32.pc.in @@ -5,7 +5,8 @@ includedir=@includedir@ Name: ecore-win32 Description: E core library, Win32 module +@pkgconfig_requires_private@: @requirements_ecore_win32@ Version: @VERSION@ Libs: -L${libdir} -lecore_win32 -Libs.private: @ddraw_libs@ @direct3d_libs@ -Cflags: -I${includedir} +Libs.private: @WIN32_LIBS@ +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-wince.pc.in b/ecore-wince.pc.in index a8275f8..c937e88 100644 --- a/ecore-wince.pc.in +++ b/ecore-wince.pc.in @@ -5,7 +5,8 @@ includedir=@includedir@ Name: ecore-wince Description: E core library, WinCE module +@pkgconfig_requires_private@: @requirements_ecore_wince@ Version: @VERSION@ Libs: -L${libdir} -lecore_wince Libs.private: @WIN32_LIBS@ -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore-x.manifest b/ecore-x.manifest new file mode 100644 index 0000000..97e8c31 --- /dev/null +++ b/ecore-x.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/ecore-x.pc.in b/ecore-x.pc.in index e134720..a02b42b 100644 --- a/ecore-x.pc.in +++ b/ecore-x.pc.in @@ -5,8 +5,8 @@ includedir=@includedir@ Name: ecore-x Description: E core library, X module -Requires: @requirements_ecore_x@ +@pkgconfig_requires_private@: @requirements_ecore_x@ Version: @VERSION@ Libs: -L${libdir} -lecore_x -Libs.private: @x_libs@ @Xcursor_libs@ @XRENDER_LIBS@ @XPRINT_LIBS@ @XINERAMA_LIBS@ @XRANDR_LIBS@ @XFIXES_LIBS@ @XDAMAGE_LIBS@ @XSS_LIBS@ @ecore_txt_libs@ -Cflags: -I${includedir} @have_ecore_x_xcb_define@ +Libs.private: @x_libs@ @ecore_x_libs_private@ +Cflags: -I${includedir}/ecore-@VMAJ@ @have_ecore_x_xcb_define@ diff --git a/ecore.pc.in b/ecore.pc.in index cd68143..db67e7a 100644 --- a/ecore.pc.in +++ b/ecore.pc.in @@ -5,8 +5,8 @@ includedir=@includedir@ Name: ecore Description: Ecore event abstraction library -Requires: +@pkgconfig_requires_private@: @requirements_ecore@ Version: @VERSION@ -Libs: -L${libdir} -lecore +Libs: -L${libdir} -lecore @EINA_LIBS@ Libs.private: -lm -Cflags: -I${includedir} +Cflags: -I${includedir}/ecore-@VMAJ@ diff --git a/ecore.spec.in b/ecore.spec.in index 78a0ce9..d70bfb5 100644 --- a/ecore.spec.in +++ b/ecore.spec.in @@ -35,10 +35,12 @@ %define ac_with_lib_ecore_imf --%{?with_lib_ecore_imf:en}%{!?with_lib_ecore_imf:dis}able-ecore-imf %define ac_with_lib_ecore_sdl --%{?with_lib_ecore_sdl:en}%{!?with_lib_ecore_sdl:dis}able-ecore-sdl +%{!?_rel:%{expand:%%global _rel 0.r%(svnversion | sed 's/[^0-9].*$//' || echo 0000)}} + Summary: Enlightened Core X interface library Name: @PACKAGE@ Version: @VERSION@ -Release: 0.%(date '+%Y%m%d') +Release: %{_rel} License: BSD Group: User Interface/X Source: %{name}-%{version}.tar.gz @@ -46,7 +48,7 @@ URL: http://www.enlightenment.org Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings } Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} -#BuildSuggests: xorg-x11-devel, XFree86-devel, libX11-devel +#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 @@ -62,20 +64,12 @@ Summary: Ecore headers and development libraries. Group: Development/Libraries Requires: %{name} = %{version} Requires: curl-devel, openssl-devel, evas-devel, eet-devel -Requires: ecore-bin, ecore-con, ecore-config, ecore-evas, ecore-file, ecore-ipc, ecore-job, ecore-txt +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 bin -Summary: Tools that support Ecore -Group: Development/Libraries -Requires: %{name} = %{version} - -%description bin -Tools that support Ecore - %package con Summary: Ecore Connection Library Group: Development/Libraries @@ -84,14 +78,6 @@ Requires: %{name} = %{version} %description con Ecore Connection Library -%package config -Summary: Ecore Enlightened Property Library -Group: Development/Libraries -Requires: %{name} = %{version} - -%description config -Ecore Enlightened Property Library - %if %{with lib_ecore_directfb} %package directfb Summary: Ecore DirectFB system functions @@ -135,29 +121,21 @@ Requires: %{name} = %{version} Ecore IMF functions %endif -%package ipc -Summary: Ecore inter-process communication functions +%package input +Summary: Ecore input functions Group: Development/Libraries Requires: %{name} = %{version} -%description ipc -Ecore inter-process communication functions +%description input +Ecore input functions -%package job -Summary: Ecore job dealing functions -Group: Development/Libraries -Requires: %{name} = %{version} - -%description job -Ecore job dealing functions - -%package txt -Summary: Ecore text encoding conversion functions +%package ipc +Summary: Ecore inter-process communication functions Group: Development/Libraries Requires: %{name} = %{version} -%description txt -Ecore text encoding conversion functions +%description ipc +Ecore inter-process communication functions %package x Summary: Ecore functions for dealing with the X Windows System @@ -168,7 +146,7 @@ Requires: %{name} = %{version} Ecore functions for dealing with the X Windows System %prep -%setup -q -n %{name}-%{version} +%setup -q %build CFLAGS="-I/usr/kerberos/include -I/usr/X11R6/include/X11/extensions" @@ -184,6 +162,7 @@ export CFLAGS LDFLAGS %install %{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install +%{find_lang} %{name} %post /sbin/ldconfig || : @@ -194,52 +173,46 @@ export CFLAGS LDFLAGS %clean test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT -%files +%files -f %{name}.lang %defattr(-, root, root) %doc AUTHORS COPYING* README* -%{_libdir}/libecore.so.* +%{_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}/*.h - -%files bin -%defattr(-, root, root) -%{_bindir}/ecore_config +%{_includedir}/ecore-1/*.h %files con %defattr(-, root, root) -%{_libdir}/libecore_con.so.* - -%files config -%defattr(-, root, root) -%{_libdir}/libecore_config.so.* +%{_libdir}/libecore_con*.so.* %if %{with lib_ecore_directfb} %files directfb %defattr(-, root, root) -%{_libdir}/libecore_directfb.so.* +%{_libdir}/libecore_directfb*.so.* %endif %files evas %defattr(-, root, root) -%{_libdir}/libecore_evas.so.* +%{_libdir}/libecore_evas*.so.* %if %{with lib_ecore_fb} %files fb %defattr(-, root, root) -%{_libdir}/libecore_fb.so.* +%{_libdir}/libecore_fb*.so.* %endif %files file %defattr(-, root, root) -%{_libdir}/libecore_file.so.* +%{_libdir}/libecore_file*.so.* %if %{with lib_ecore_imf} %files imf @@ -247,18 +220,14 @@ test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT %{_libdir}/libecore_imf*.so.* %endif -%files ipc +%files input %defattr(-, root, root) -%{_libdir}/libecore_ipc.so.* +%{_libdir}/libecore_input*.so.* -%files job -%defattr(-, root, root) -%{_libdir}/libecore_job.so.* - -%files txt +%files ipc %defattr(-, root, root) -%{_libdir}/libecore_txt.so.* +%{_libdir}/libecore_ipc*.so.* %files x %defattr(-, root, root) -%{_libdir}/libecore_x.so.* +%{_libdir}/libecore_x*.so.* diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4 index 46c1a42..23479a9 100644 --- a/m4/ac_attribute.m4 +++ b/m4/ac_attribute.m4 @@ -1,14 +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)]) - if test "$ac_cv___attribute__" = "yes"; then - AC_DEFINE(HAVE___ATTRIBUTE__, 1, [Define to 1 if your compiler has __attribute__]) - fi - AC_MSG_RESULT($ac_cv___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 index 41fb8c1..a15120c 100644 --- a/m4/check_x_extension.m4 +++ b/m4/check_x_extension.m4 @@ -1,4 +1,4 @@ -dnl use: ECORE_CHECK_X_EXTENSION(Foo, header, lib, func) +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 @@ -8,24 +8,29 @@ UP[]_CFLAGS="" UP[]_LIBS="" use_[]DOWN="no" -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 +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) diff --git a/m4/ecore_check_module.m4 b/m4/ecore_check_module.m4 index 8859c52..01c4e0e 100644 --- a/m4/ecore_check_module.m4 +++ b/m4/ecore_check_module.m4 @@ -1,99 +1,97 @@ -dnl use: ECORE_CHECK_MODULE(Foo, default-enabled[, dependancy[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]]) +dnl use: ECORE_CHECK_MODULE(Foo, default-enabled, description[, dependency[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]]) AC_DEFUN([ECORE_CHECK_MODULE], [ -pushdef([UP], translit([$1], [a-z], [A-Z]))dnl -pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl +m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl +m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl -have_ecore_[]DOWN="no" -ecore_[]DOWN[]_cflags="" -ecore_[]DOWN[]_libs="" +have_ecore_[]m4_defn([DOWN])=no +ecore_[]m4_defn([DOWN])[]_cflags= +ecore_[]m4_defn([DOWN])[]_libs= +want_module=$2 -ifelse("x$2", "xno", -[ - AC_ARG_ENABLE(ecore-[]DOWN, - AC_HELP_STRING( - [--enable-ecore-[]DOWN], - [enable the ecore_[]DOWN module. [[default=disabled]]] - ), - [ want_ecore_[]DOWN=$enableval ], - [ want_ecore_[]DOWN=no ]) -], -[ - AC_ARG_ENABLE(ecore-[]DOWN, - AC_HELP_STRING( - [--disable-ecore-[]DOWN], - [disable the ecore_[]DOWN module. [[default=enabled]]] - ), - [ want_ecore_[]DOWN=$enableval ], - [ want_ecore_[]DOWN=yes ]) -]) +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]) -AC_MSG_CHECKING(whether ecore_[]DOWN module is to be built) - -if test "x$want_ecore_[]DOWN" = "xyes" ; then - if test "x$3" = "x" -o "x$3" = "xyes" ; then - AC_DEFINE(BUILD_ECORE_[]UP, 1, [Build Ecore_$1 Module]) - have_ecore_[]DOWN="yes" - ecore_[]DOWN[]_libs="-lecore_[]DOWN" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no (dependancy failed)]) - fi +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]) + AC_MSG_RESULT([no]) fi -AM_CONDITIONAL(BUILD_ECORE_[]UP, test "x$have_ecore_[]DOWN" = "xyes") +AM_CONDITIONAL([BUILD_ECORE_]UP, [test "x$have_ecore_]DOWN[" = "xyes"]) -if test "x$have_ecore_[]DOWN" = "xyes" ; then - ifelse([$4], , :, [$4]) -else - ifelse([$5], , :, [$5]) -fi +AS_IF([test "x$have_ecore_[]m4_defn([DOWN])" = "xyes"], [$5], [$6]) -AC_SUBST(ecore_[]DOWN[]_cflags) -AC_SUBST(ecore_[]DOWN[]_libs) +AC_SUBST(ecore_[]m4_defn([DOWN])[]_cflags) +AC_SUBST(ecore_[]m4_defn([DOWN])[]_libs) -popdef([UP]) -popdef([DOWN]) +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], +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], [ -pushdef([UP], translit([$1], [-a-z], [_A-Z]))dnl -pushdef([DOWN], translit([$1], [-A-Z], [_a-z]))dnl +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_[]DOWN="no" -want_module="$2" +have_ecore_evas_[]m4_defn([DOWN])="no" +want_module="$3" -AC_ARG_ENABLE(ecore-$1, - AC_HELP_STRING( - [--enable-ecore-evas-$1], - [enable $3 support in the ecore_evas module.] - ), - [ want_module=$enableval ] -) -AC_MSG_CHECKING(whether ecore_evas $3 support is to be built) -AC_MSG_RESULT($want_module) - -if test "x$4" = "xyes" -a \ - "x$have_ecore_evas" = "xyes" -a \ - "x$want_module" = "xyes" ; then - PKG_CHECK_MODULES(EVAS_[]UP, evas-$1, - [ - AC_DEFINE(BUILD_ECORE_EVAS_[]UP, 1, [Support for $3 Engine in Ecore_Evas]) - have_ecore_evas_[]DOWN="yes"; - ] - ) -fi +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 + ], + []) -if test "x$have_ecore_evas_[]DOWN" = "xyes" ; then - ifelse([$5], , :, [$5]) -else - ifelse([$6], , :, [$6]) +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 -popdef([UP]) -popdef([DOWN]) +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/packaging/ecore.changes b/packaging/ecore.changes new file mode 100644 index 0000000..a716b5b --- /dev/null +++ b/packaging/ecore.changes @@ -0,0 +1,3 @@ +* Fri Jan 18 2013 Anas Nashif accepted/trunk/20130117.015224@eb8e0c9 +- devel requires sub-packages and other spec fixes + diff --git a/packaging/ecore.spec b/packaging/ecore.spec new file mode 100644 index 0000000..f53f848 --- /dev/null +++ b/packaging/ecore.spec @@ -0,0 +1,311 @@ +Name: ecore +Summary: Enlightened Core X interface library +Version: 1.7.1+svn.77580+build01r01 +Release: 1 +Group: System/Libraries +License: BSD +URL: http://www.enlightenment.org +Source0: %{name}-%{version}.tar.gz +BuildRequires: gettext-tools +BuildRequires: pkgconfig(eina) +BuildRequires: pkgconfig(eet) +BuildRequires: pkgconfig(evas) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(xcursor) +BuildRequires: pkgconfig(xrender) +BuildRequires: pkgconfig(xinerama) +BuildRequires: pkgconfig(xrandr) +BuildRequires: pkgconfig(xext) +BuildRequires: pkgconfig(xi) +BuildRequires: pkgconfig(xfixes) +BuildRequires: pkgconfig(xcomposite) +BuildRequires: pkgconfig(xdamage) +BuildRequires: pkgconfig(xextproto) +BuildRequires: pkgconfig(xtst) +BuildRequires: curl-devel +BuildRequires: libjpeg-devel +BuildRequires: pkgconfig(xgesture) + + +%description +Core abstraction layer for enlightenment DR 0.17 This is the core event abstraction layer and X abstraction layer that makes + doing selections, Xdnd, general X stuff, and 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: Enlightened Core X interface library (devel) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Requires: ecore-file +Requires: ecore-evas +Requires: ecore-fb +Requires: ecore-imf +Requires: ecore-imf-evas +Requires: ecore-input +Requires: ecore-input-evas +Requires: ecore-ipc +Requires: ecore-x +Requires: ecore-con + +%description devel +Core abstraction layer for enlightenment (devel) + +%package tools +Summary: Enlightened Core X interface library (bin) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} +Provides: %{name}-bin +Obsoletes: %{name}-bin + +%description tools +Core abstraction layer for enlightenment (tools) + +%package con +Summary: Enlightened Core X interface library (con) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description con +Core abstraction layer for enlightenment (con) + +%package evas +Summary: Enlightened Core X interface library (evas) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description evas +Core abstraction layer for enlightenment (evas) + +%package file +Summary: Enlightened Core X interface library (file) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description file +Core abstraction layer for enlightenment (file) + +%package imf +Summary: Enlightened Core X interface library (imf) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description imf +Core abstraction layer for enlightenment (imf) + +%package imf-evas +Summary: Enlightened Core X interface library (imf-evas) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description imf-evas +Core abstraction layer for enlightenment (imf-evas) + +%package input +Summary: Enlightened Core X interface library (input) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description input +Core abstraction layer for enlightenment (input) + +%package input-evas +Summary: Enlightened Core X interface library (input-evas) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description input-evas +Core abstraction layer for enlightenment (input-evas) + +%package ipc +Summary: Enlightened Core X interface library (ipc) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description ipc +Core abstraction layer for enlightenment (ipc) + +%package x +Summary: Enlightened Core X interface library (x) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description x +Core abstraction layer for enlightenment (x) + +%package fb +Summary: Enlightened Core X interface library (fb) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description fb +Core abstraction layer for enlightenment (fb) + + +%prep +%setup -q + + +%build +export CFLAGS+=" -fvisibility=hidden -fPIC" +export LDFLAGS+=" -fvisibility=hidden -Wl,--hash-style=both -Wl,--as-needed" + +%autogen +%configure --disable-static \ + --enable-ecore-fb \ + --enable-dependency-tracking \ + --disable-ecore-directfb \ + --enable-ecore-evas-fb \ + --disable-rpath \ + --disable-openssl \ + --disable-gnutls \ + --disable-tslib \ + --enable-simple-x11 \ + --enable-ecore-evas-opengl-x11 \ + --disable-ecore-evas-xrender-x11 \ + --enable-curl \ + --enable-glib-integration-always \ + --enable-ecore-x-gesture \ + --disable-xim \ + --disable-ecore-imf-xim \ + --disable-ecore-imf-scim + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install +mkdir -p %{buildroot}/usr/share/license +cp %{_builddir}/%{buildsubdir}/COPYING %{buildroot}/usr/share/license/%{name} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%post con -p /sbin/ldconfig + +%postun con -p /sbin/ldconfig + +%post evas -p /sbin/ldconfig + +%postun evas -p /sbin/ldconfig + + +%post file -p /sbin/ldconfig + +%postun file -p /sbin/ldconfig + + +%post imf -p /sbin/ldconfig + +%postun imf -p /sbin/ldconfig + + +%post imf-evas -p /sbin/ldconfig + +%postun imf-evas -p /sbin/ldconfig + + +%post input -p /sbin/ldconfig + +%postun input -p /sbin/ldconfig + + +%post input-evas -p /sbin/ldconfig + +%postun input-evas -p /sbin/ldconfig + + +%post ipc -p /sbin/ldconfig + +%postun ipc -p /sbin/ldconfig + + +%post x -p /sbin/ldconfig + +%postun x -p /sbin/ldconfig + + +%post fb -p /sbin/ldconfig + +%postun fb -p /sbin/ldconfig + +%files +%defattr(-,root,root,-) +%{_libdir}/libecore.so.* +/usr/share/locale/* +/usr/share/license/%{name} + +%files devel +%defattr(-,root,root,-) +%{_includedir}/ecore-1/*.h +%{_libdir}/pkgconfig/ecore*.pc +%{_libdir}/libecore.so +%{_libdir}/libecore_con.so +%{_libdir}/libecore_evas.so +%{_libdir}/libecore_file.so +%{_libdir}/libecore_imf.so +%{_libdir}/libecore_imf_evas.so +%{_libdir}/libecore_input.so +%{_libdir}/libecore_input_evas.so +%{_libdir}/libecore_ipc.so +%{_libdir}/libecore_x.so +%{_libdir}/libecore_fb.so + +%files tools +%defattr(-,root,root,-) +#/usr/bin/ecore_test + +%files con +%defattr(-,root,root,-) +%{_libdir}/libecore_con.so.* +%manifest %{name}-con.manifest + +%files evas +%defattr(-,root,root,-) +%{_libdir}/libecore_evas.so.* +%manifest %{name}-evas.manifest + +%files file +%defattr(-,root,root,-) +%{_libdir}/libecore_file.so.* +%manifest %{name}-file.manifest + +%files imf +%defattr(-,root,root,-) +%{_libdir}/libecore_imf.so.* +%manifest %{name}-imf.manifest + +%files imf-evas +%defattr(-,root,root,-) +%{_libdir}/libecore_imf_evas.so.* +%manifest %{name}-imf-evas.manifest + +%files input +%defattr(-,root,root,-) +%{_libdir}/libecore_input.so.* +%manifest %{name}-input.manifest + +%files input-evas +%defattr(-,root,root,-) +%{_libdir}/libecore_input_evas.so.* +%manifest %{name}-input-evas.manifest + +%files ipc +%defattr(-,root,root,-) +%{_libdir}/libecore_ipc.so.* +%manifest %{name}-ipc.manifest + +%files x +%defattr(-,root,root,-) +%{_libdir}/libecore_x.so.* +%manifest %{name}-x.manifest + +%files fb +%defattr(-,root,root,-) +%{_libdir}/libecore_fb.so.* +%manifest %{name}-fb.manifest + 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..c58c323 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +cs de el fr it ko 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/ko.po b/po/ko.po new file mode 100644 index 0000000..abc5e37 --- /dev/null +++ b/po/ko.po @@ -0,0 +1,185 @@ +# Korean translation for the Enlightenment ecore. +# Copyright (C) 2000-2012 Enlightenment development team +# This file is distributed under the same license as the Enlightenment package. +# Seong-ho Cho , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: Enlightenment Ecore 1.7.0\n" +"Report-Msgid-Bugs-To: Enlightenment-Devel \n" +"POT-Creation-Date: 2012-08-30 22:29+0900\n" +"PO-Revision-Date: 2012-08-30 22:50+0900\n" +"Last-Translator: Seong-ho Cho \n" +"Language-Team: Enlightenment-Intl \n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Poedit-Language: Korean\n" +"X-Poedit-Country: KOREA, REPUBLIC OF\n" +"X-Poedit-SourceCharset: utf-8\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 "알 수 없는 부울린 값 %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 "오류: -%c 옵션에 인자가 필요합니다!\n" + +#: src/lib/ecore/ecore_getopt.c:1793 +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" + 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 index a8590b2..b8dab4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,26 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = lib bin +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 index bc2c0dd..79110e4 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -8,6 +8,10 @@ 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 \ @@ -16,9 +20,9 @@ AM_CPPFLAGS = \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ -@EET_CFLAGS@ +@EINA_CFLAGS@ @EVAS_CFLAGS@ -bin_PROGRAMS = $(ECORE_CONFIG_PROG) +bin_PROGRAMS = $(ECORE_CONFIG_PROG) $(ECORE_TEST_PROG) ecore_config_SOURCES = \ ecore_config.c @@ -27,10 +31,21 @@ 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 +$(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 index e3ef78c..b4973d9 100644 --- a/src/bin/ecore_config.c +++ b/src/bin/ecore_config.c @@ -10,7 +10,6 @@ #include #include #include "Ecore_Config.h" -#include "Ecore_Data.h" #include "ecore_config_private.h" // strcmp for paths - for sorting folders before files @@ -37,8 +36,8 @@ pathcmp(const char *s1, const char *s2) // order folders before files s1d = strchr(s1, '/'); s2d = strchr(s2, '/'); - if (s1d != NULL && s2d == NULL) return -1; - if (s1d == NULL && s2d != NULL) return 1; + if (s1d && !s2d) return -1; + if (!s1d && s2d) return 1; return strcmp(s1, s2); } @@ -48,7 +47,7 @@ del(const char *key) { Ecore_Config_Prop *e; e = ecore_config_get(key); - if(e == NULL) return -1; + if(!e) return -1; ecore_config_dst(e); return 0; @@ -62,7 +61,7 @@ get(const char *key) if (!(e = ecore_config_get(key))) { - fprintf(stderr, "No such property\n"); + EINA_LOG_ERR("No such property"); return -1; } @@ -92,7 +91,7 @@ get(const char *key) temp = ecore_config_theme_get(key); break; default: - fprintf(stderr, "Property has unrecognized type"); + EINA_LOG_ERR("Property has unrecognized type"); return -1; } if(temp) @@ -106,19 +105,9 @@ get(const char *key) static int list(const char *file) { - char *key; - - Eet_File *ef; Ecore_Config_Prop *e; - Ecore_Sheap *keys; - - // Get number of keys and create heap for sort - ef = eet_open(file, EET_FILE_MODE_READ); - if (!ef) return -1; - - keys = ecore_sheap_new(ECORE_COMPARE_CB(pathcmp), eet_num_entries(ef)); - - eet_close(ef); + Eina_List *keys = NULL; + char *key; e = __ecore_config_bundle_local->data; @@ -126,18 +115,17 @@ list(const char *file) { // don't show system settings if( !(e->flags & ECORE_CONFIG_FLAG_SYSTEM) ) - ecore_sheap_insert(keys, e->key); + keys = eina_list_append(keys, e->key); } while((e = e->next)); + keys = eina_list_sort(keys, -1, EINA_COMPARE_CB(pathcmp)); - while((key = ecore_sheap_extract(keys))) + EINA_LIST_FREE(keys, key) { printf("%-28s\t", key); get(key); } - ecore_sheap_destroy(keys); - return 0; } @@ -175,7 +163,7 @@ main(int argc, char * const argv[]) float f; file = key = prog = NULL; - + eina_init(); prog = strdup(argv[0]); if(argc < 4) @@ -270,12 +258,12 @@ main(int argc, char * const argv[]) if(cmd == 's' && type == -1) usage_and_exit(prog, 2, "You need to specify a command!"); - if(cmd != 'a' && key == NULL) + if(cmd != 'a' && !key) usage_and_exit(prog, 2, "You need to specify key!"); if(ecore_config_init("econfig") != ECORE_CONFIG_ERR_SUCC) { - fprintf(stderr, "Couldn't init ecore_config!"); + EINA_LOG_ERR("Couldn't init ecore_config!"); return 1; } @@ -313,7 +301,7 @@ main(int argc, char * const argv[]) if (list(file)) ret = 1; break; default: - printf("Unhandled command '%c'\n", cmd); + EINA_LOG_ERR("Unhandled command '%c'", cmd); } ecore_config_shutdown(); @@ -323,7 +311,7 @@ main(int argc, char * const argv[]) if(file) free(file); - + eina_shutdown(); return ret; } #else 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 index 67efd6c..d43ad75 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -1,19 +1,75 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = \ -ecore \ -ecore_job \ -ecore_txt \ -ecore_fb \ -ecore_directfb \ -ecore_con \ -ecore_x \ -ecore_win32 \ -ecore_wince \ -ecore_sdl \ -ecore_ipc \ -ecore_evas \ -ecore_config \ -ecore_file \ -ecore_desktop \ -ecore_imf \ -ecore_imf_evas +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 index b79a9cd..d47c24d 100644 --- a/src/lib/ecore/Ecore.h +++ b/src/lib/ecore/Ecore.h @@ -1,6 +1,333 @@ +/** + @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 @@ -27,47 +354,286 @@ # 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); +/** + * @} + */ + /** - * @file Ecore.h - * @brief The file that provides the program utility, main loop and timer - * functions. + * @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. * - * This header provides the Ecore event handling loop. For more - * details, see @ref Ecore_Main_Loop_Group. + * For details on the usage of ecore's main loop and how it interacts with other + * ecore facilities see: @ref Ecore_Main_Loop_Page. * - * For the main loop to be of any use, you need to be able to add events - * and event handlers. Events for file descriptor events are covered in - * @ref Ecore_FD_Handler_Group. + * @{ + */ + +#define ECORE_VERSION_MAJOR 1 +#define ECORE_VERSION_MINOR 8 + +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 * - * Time functions are covered in @ref Ecore_Time_Group. + * @param callback The callback to call in the main loop + * @param data The data to give to that call back * - * There is also provision for callbacks for when the loop enters or - * exits an idle state. See @ref Idle_Group for more information. + * 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. * - * Functions are also provided for spawning child processes using fork. - * See @ref Ecore_Exe_Basic_Group and @ref Ecore_Exe_Signal_Group for - * more details. + * 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); -#ifndef _ECORE_PRIVATE_H -#include -#include -#endif +/** + * @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); -#ifndef TRUE -#define TRUE 1 -#endif +/** + * @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); -#ifndef FALSE -#define FALSE 0 -#endif +/** + * @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); -#ifdef __cplusplus -extern "C" { -#endif +/** + * @} + */ -#define ECORE_CALLBACK_CANCEL 0 /**< Return value to remove a callback */ -#define ECORE_CALLBACK_RENEW 1 /**< Return value to keep a callback */ +/** + * @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 */ @@ -77,229 +643,1975 @@ extern "C" { #define ECORE_EVENT_SIGNAL_REALTIME 5 /**< Realtime signal event */ #define ECORE_EVENT_COUNT 6 - 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 consistant 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. */ - -#ifndef _ECORE_PRIVATE_H - 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; - - enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or stdout piped back */ - { - 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 delivered 1 event per line */ - ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered until a newline and delivered 1 event per 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 */ - }; - typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; - - enum _Ecore_Poller_Type /* Poller types */ - { - ECORE_POLLER_CORE = 0 /**< The core poller interval */ - }; - typedef enum _Ecore_Poller_Type Ecore_Poller_Type; - -#ifndef _WIN32 - typedef void Ecore_Exe; /**< A handle for spawned processes */ -#endif - typedef void Ecore_Timer; /**< A handle for timers */ - typedef void Ecore_Idler; /**< A handle for idlers */ - typedef void Ecore_Idle_Enterer; /**< A handle for idle enterers */ - typedef void Ecore_Idle_Exiter; /**< A handle for idle exiters */ - typedef void Ecore_Fd_Handler; /**< A handle for Fd hanlders */ - typedef void Ecore_Event_Handler; /**< A handle for an event handler */ - typedef void Ecore_Event_Filter; /**< A handle for an event filter */ - typedef void Ecore_Event; /**< A handle for an event */ - typedef void Ecore_Animator; /**< A handle for animators */ - typedef void Ecore_Poller; /**< A handle for pollers */ -#endif - 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 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_Event_Signal_User /** User signal event */ - { - int number; /**< The signal number. Either 1 or 2 */ - void *ext_data; /**< Extension data - not used */ - -#ifndef _WIN32 - siginfo_t data; /**< Signal info */ -#endif - }; +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_Hup /** Hup signal event */ - { - void *ext_data; /**< Extension data - not used */ +struct _Ecore_Event_Signal_User /** User signal event */ +{ + int number; /**< The signal number. Either 1 or 2 */ + void *ext_data; /**< Extension data - not used */ -#ifndef _WIN32 - siginfo_t data; /**< Signal info */ +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ #endif - }; +}; - struct _Ecore_Event_Signal_Exit /** Exit request event */ - { - unsigned int interrupt : 1; /**< Set if the exit request was an interrupt signal*/ - unsigned int quit : 1; /**< set if the exit request was a quit signal */ - unsigned int terminate : 1; /**< Set if the exit request was a terminate singal */ - void *ext_data; /**< Extension data - not used */ +struct _Ecore_Event_Signal_Hup /** Hup signal event */ +{ + void *ext_data; /**< Extension data - not used */ -#ifndef _WIN32 - siginfo_t data; /**< Signal info */ +#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 */ +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 */ -#ifndef _WIN32 - siginfo_t data; /**< Signal info */ +#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 */ +struct _Ecore_Event_Signal_Power /** Power event */ +{ + void *ext_data; /**< Extension data - not used */ -#ifndef _WIN32 - siginfo_t data; /**< Signal info */ +#if !defined (_WIN32) && !defined (__lv2ppu__) && !defined (EXOTIC_NO_SIGNAL) + siginfo_t data; /**< Signal info */ #endif - }; - -#ifndef _WIN32 - 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 NULL if not found */ - int exit_signal; /** < The signal that caused the process to exit */ - unsigned int exited : 1; /** < set to 1 if the process exited of its own accord */ - unsigned int signalled : 1; /** < set to 1 id the process exited due to uncaught signal */ - void *ext_data; /**< Extension data - not used */ - siginfo_t data; /**< Signal info */ - }; - - struct _Ecore_Exe_Event_Data_Line /**< Lines from a child process */ - { - char *line; - int size; - }; - - 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 recieved */ - 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 NULL */ - }; +}; + +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 int ecore_init(void); - EAPI int ecore_shutdown(void); - - 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); - - EAPI Ecore_Event_Handler *ecore_event_handler_add(int type, int (*func) (void *data, int type, void *event), const void *data); - EAPI void *ecore_event_handler_del(Ecore_Event_Handler *event_handler); - EAPI Ecore_Event *ecore_event_add(int type, void *ev, void (*func_free) (void *data, void *ev), void *data); - EAPI void *ecore_event_del(Ecore_Event *event); - EAPI int ecore_event_type_new(void); - EAPI Ecore_Event_Filter *ecore_event_filter_add(void * (*func_start) (void *data), int (*func_filter) (void *data, void *loop_data, int type, void *event), void (*func_end) (void *data, void *loop_data), const void *data); - EAPI void *ecore_event_filter_del(Ecore_Event_Filter *ef); - EAPI int ecore_event_current_type_get(void); - EAPI void *ecore_event_current_event_get(void); - - -#ifndef _WIN32 - 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 int ecore_exe_send(Ecore_Exe *exe, 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(Ecore_Exe *exe); - EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag); - EAPI char *ecore_exe_tag_get(Ecore_Exe *exe); - EAPI char *ecore_exe_cmd_get(Ecore_Exe *exe); - EAPI void *ecore_exe_data_get(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); +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); - EAPI Ecore_Idler *ecore_idler_add(int (*func) (void *data), const void *data); - EAPI void *ecore_idler_del(Ecore_Idler *idler); - - EAPI Ecore_Idle_Enterer *ecore_idle_enterer_add(int (*func) (void *data), const void *data); - EAPI Ecore_Idle_Enterer *ecore_idle_enterer_before_add(int (*func) (void *data), const void *data); - EAPI void *ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer); - - EAPI Ecore_Idle_Exiter *ecore_idle_exiter_add(int (*func) (void *data), const void *data); - EAPI void *ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter); - - EAPI void ecore_main_loop_iterate(void); - EAPI void ecore_main_loop_begin(void); - EAPI void ecore_main_loop_quit(void); - EAPI Ecore_Fd_Handler *ecore_main_fd_handler_add(int fd, Ecore_Fd_Handler_Flags flags, int (*func) (void *data, Ecore_Fd_Handler *fd_handler), const void *data, int (*buf_func) (void *buf_data, Ecore_Fd_Handler *fd_handler), const void *buf_data); - EAPI void ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, void (*func) (void *data, Ecore_Fd_Handler *fd_handler), const void *data); - EAPI void *ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler); - EAPI int ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler); - EAPI int ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags); - EAPI void ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags); - - EAPI double ecore_time_get(void); - - EAPI Ecore_Timer *ecore_timer_add(double in, int (*func) (void *data), const void *data); - EAPI void *ecore_timer_del(Ecore_Timer *timer); - EAPI void ecore_timer_interval_set(Ecore_Timer *timer, double in); - 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 double ecore_timer_pending_get(Ecore_Timer *timer); - - EAPI Ecore_Animator *ecore_animator_add(int (*func) (void *data), const void *data); - EAPI void *ecore_animator_del(Ecore_Animator *animator); - EAPI void ecore_animator_frametime_set(double frametime); - EAPI double ecore_animator_frametime_get(void); - - EAPI void ecore_poller_poll_interval_set(Ecore_Poller_Type type, double poll_time); - EAPI double ecore_poller_poll_interval_get(Ecore_Poller_Type type); - EAPI Ecore_Poller *ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), const void *data); - EAPI void *ecore_poller_del(Ecore_Poller *poller); +/** + * @} + */ + +/** + * @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 } 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 index 4c692bb..6f14387 100644 --- a/src/lib/ecore/Makefile.am +++ b/src/lib/ecore/Makefile.am @@ -1,38 +1,69 @@ MAINTAINERCLEANFILES = Makefile.in -AM_CFLAGS = @WIN32_CFLAGS@ +AM_CPPFLAGS = @GLIB_CFLAGS@ @EVIL_CFLAGS@ @EINA_CFLAGS@ @WIN32_CPPFLAGS@ @EFL_ECORE_BUILD@ +AM_CFLAGS = @WIN32_CFLAGS@ @EFL_PTHREAD_CFLAGS@ lib_LTLIBRARIES = libecore.la -include_HEADERS = \ +includes_HEADERS = \ Ecore.h \ -Ecore_Data.h \ -Ecore_Str.h +Ecore_Getopt.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_la_SOURCES = \ ecore.c \ -ecore_app.c \ +ecore_alloc.c \ ecore_anim.c \ +ecore_app.c \ ecore_events.c \ -ecore_exe.c \ -ecore_hash.c \ +ecore_getopt.c \ ecore_idle_enterer.c \ ecore_idle_exiter.c \ ecore_idler.c \ -ecore_list.c \ +ecore_job.c \ ecore_main.c \ -ecore_path.c \ -ecore_plugin.c \ -ecore_sheap.c \ -ecore_signal.c \ -ecore_str.c \ -ecore_strbuf.c \ -ecore_strings.c \ +ecore_pipe.c \ +ecore_poll.c \ ecore_time.c \ ecore_timer.c \ -ecore_tree.c \ -ecore_value.c \ -ecore_poll.c \ -ecore_private.h +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@ -libecore_la_LIBADD = @dlopen_libs@ @EVIL_LIBS@ @WIN32_LIBS@ -lm -libecore_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +EXTRA_DIST = ecore_private.h diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c index 7ac32fa..0df319b 100644 --- a/src/lib/ecore/ecore.c +++ b/src/lib/ecore/ecore.c @@ -1,8 +1,18 @@ - #ifdef HAVE_CONFIG_H # include #endif +#include +#include +#include +#include +#include +#include + +#ifndef _MSC_VER +# include +#endif + #ifdef HAVE_LOCALE_H # include #endif @@ -11,18 +21,81 @@ # include #endif -#include "Ecore.h" -#include "ecore_private.h" +#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 ?? */ @@ -32,6 +105,12 @@ int _ecore_fps_debug = 0; #endif /** + * @addtogroup Ecore_Init_Group + * + * @{ + */ + +/** * Set up connections, signal handlers, sockets etc. * @return 1 or greater on success, 0 otherwise * @@ -56,29 +135,83 @@ int _ecore_fps_debug = 0; EAPI int ecore_init(void) { - if (++_ecore_init_count == 1) - { + if (++_ecore_init_count != 1) + return _ecore_init_count; + #ifdef HAVE_LOCALE_H - setlocale(LC_CTYPE, ""); + 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 (strcmp(nl_langinfo(CODESET), "UTF-8")) - { - printf("WARNING: not a utf8 locale!\n"); - } - */ - if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1; - if (_ecore_fps_debug) _ecore_fps_debug_init(); - _ecore_signal_init(); - _ecore_exe_init(); + 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. @@ -89,46 +222,353 @@ ecore_init(void) EAPI int ecore_shutdown(void) { - if (--_ecore_init_count) - return _ecore_init_count; - - if (_ecore_fps_debug) _ecore_fps_debug_shutdown(); - _ecore_poller_shutdown(); - _ecore_animator_shutdown(); - _ecore_exe_shutdown(); - _ecore_idle_enterer_shutdown(); - _ecore_idle_exiter_shutdown(); - _ecore_idler_shutdown(); - _ecore_timer_shutdown(); - _ecore_event_shutdown(); - _ecore_main_shutdown(); - _ecore_signal_shutdown(); + 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(); - return _ecore_init_count; + /* 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(void *d, Ecore_Magic m, Ecore_Magic req_m, const char *fname) +_ecore_magic_fail(const void *d, + Ecore_Magic m, + Ecore_Magic req_m, + const char *fname __UNUSED__) { - fprintf(stderr, - "\n" - "*** ECORE ERROR: Ecore Magic Check Failed!!!\n" - "*** IN FUNCTION: %s()\n", fname); + ERR("\n" + "*** ECORE ERROR: Ecore Magic Check Failed!!!\n" + "*** IN FUNCTION: %s()", fname); if (!d) - fprintf(stderr, " Input handle pointer is NULL!\n"); + ERR(" Input handle pointer is NULL!"); else if (m == ECORE_MAGIC_NONE) - fprintf(stderr, " Input handle has already been freed!\n"); + ERR(" Input handle has already been freed!"); else if (m != req_m) - fprintf(stderr, " Input handle is wrong type\n" - " Expected: %08x - %s\n" - " Supplied: %08x - %s\n", - (unsigned int)req_m, _ecore_magic_string_get(req_m), - (unsigned int)m, _ecore_magic_string_get(m)); - fprintf(stderr, - "*** NAUGHTY PROGRAMMER!!!\n" - "*** SPANK SPANK SPANK!!!\n" - "*** Now go fix your code. Tut tut tut!\n" - "\n"); + 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(); } @@ -138,36 +578,48 @@ _ecore_magic_string_get(Ecore_Magic m) switch (m) { case ECORE_MAGIC_NONE: - return "None (Freed Object)"; - break; + return "None (Freed Object)"; + break; + case ECORE_MAGIC_EXE: - return "Ecore_Exe (Executable)"; - break; + return "Ecore_Exe (Executable)"; + break; + case ECORE_MAGIC_TIMER: - return "Ecore_Timer (Timer)"; - break; + return "Ecore_Timer (Timer)"; + break; + case ECORE_MAGIC_IDLER: - return "Ecore_Idler (Idler)"; - break; + return "Ecore_Idler (Idler)"; + break; + case ECORE_MAGIC_IDLE_ENTERER: - return "Ecore_Idle_Enterer (Idler Enterer)"; - break; + return "Ecore_Idle_Enterer (Idler Enterer)"; + break; + case ECORE_MAGIC_IDLE_EXITER: - return "Ecore_Idle_Exiter (Idler Exiter)"; - break; + return "Ecore_Idle_Exiter (Idler Exiter)"; + break; + case ECORE_MAGIC_FD_HANDLER: - return "Ecore_Fd_Handler (Fd Handler)"; - break; + 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; + return "Ecore_Event_Handler (Event Handler)"; + break; + case ECORE_MAGIC_EVENT: - return "Ecore_Event (Event)"; - break; + return "Ecore_Event (Event)"; + break; + default: - return ""; - }; - return ""; + return ""; + } } /* fps debug calls - for debugging how much time your app actually spends */ @@ -181,9 +633,9 @@ unsigned int *_ecore_fps_runtime_mmap = NULL; void _ecore_fps_debug_init(void) { - char buf[4096]; - char *tmp; - int pid; + char buf[PATH_MAX]; + const char *tmp; + int pid; _ecore_fps_debug_init_count++; if (_ecore_fps_debug_init_count > 1) return; @@ -191,27 +643,47 @@ _ecore_fps_debug_init(void) #ifndef HAVE_EVIL tmp = "/tmp"; #else - tmp = (char *)evil_tmpdir_get (); + 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); + 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; - - write(_ecore_fps_debug_fd, &zero, sizeof(unsigned int)); - _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; + 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; } } @@ -222,25 +694,25 @@ _ecore_fps_debug_shutdown(void) if (_ecore_fps_debug_init_count > 0) return; if (_ecore_fps_debug_fd >= 0) { - char buf[4096]; - char *tmp; - int pid; + char buf[4096]; + const char *tmp; + int pid; #ifndef HAVE_EVIL - tmp = "/tmp"; + tmp = "/tmp"; #else - tmp = (char *)evil_tmpdir_get (); + 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; + 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; } } @@ -250,15 +722,133 @@ _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; + 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 index 7c24813..67bf8b1 100644 --- a/src/lib/ecore/ecore_anim.c +++ b/src/lib/ecore/ecore_anim.c @@ -1,168 +1,516 @@ -#include "ecore_private.h" +#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; +}; -static int _ecore_animator(void *data); +GENERIC_ALLOC_SIZE_DECLARE(Ecore_Animator); -static Ecore_Timer *timer = NULL; -static int animators_delete_me = 0; +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; - -/** - * Add a animator to tick off at every animaton 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 - * @ingroup Ecore_Animator_Group - * - * This function adds a animator and returns its handle on success and NULL on - * failure. The function @p func will be called every N seconds where N is the - * 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. - */ -EAPI Ecore_Animator * -ecore_animator_add(int (*func) (void *data), const void *data) +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; - - if (!func) return NULL; - animator = calloc(1, sizeof(Ecore_Animator)); - if (!animator) return NULL; + + 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; - animators = _ecore_list2_append(animators, animator); - if (!timer) - timer = ecore_timer_add(animators_frametime, _ecore_animator, NULL); + 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; } -/** - * Delete the specified animator from the animator list. - * @param animator The animator to delete - * @return The data pointer set for the animator - * @ingroup Ecore_Animator_Group - * - * Delete the specified @p aqnimator 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 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 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"); - return NULL; + ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR, + "ecore_animator_del"); + goto unlock; } - if (animator->delete_me) return animator->data; - animator->delete_me = 1; + if (animator->delete_me) + { + data = animator->data; + goto unlock; + } + animator->delete_me = EINA_TRUE; animators_delete_me++; - return animator->data; + if (animator->run_func) + data = animator->run_data; + else + data = animator->data; +unlock: + _ecore_unlock(); + return data; } -/** - * 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) inbetween animator ticks. - */ 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) return; + if (animators_frametime == frametime) goto unlock; animators_frametime = frametime; - if (timer) - { - ecore_timer_del(timer); - timer = NULL; - } - if (animators) - timer = ecore_timer_add(animators_frametime, _ecore_animator, NULL); + _end_tick(); + if (animators) _begin_tick(); +unlock: + _ecore_unlock(); } -/** - * Get the animator call interval in seconds. - * @return The time in second in between animator ticks. - * - * this function retrieves the time inbetween animator ticks, in seconds. - */ EAPI double ecore_animator_frametime_get(void) { + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); return animators_frametime; } -void -_ecore_animator_shutdown(void) +EAPI void +ecore_animator_freeze(Ecore_Animator *animator) { - if (timer) - { - ecore_timer_del(timer); - timer = NULL; - } - while (animators) + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR)) { - Ecore_Animator *animator; - - animator = animators; - animators = _ecore_list2_remove(animators, animator); - ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE); - free(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(); } -static int -_ecore_animator(void *data __UNUSED__) +EAPI void +ecore_animator_thaw(Ecore_Animator *animator) { - Ecore_List2 *l; - - for (l = (Ecore_List2 *)animators; l;) + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR)) { - Ecore_Animator *animator; - - animator = (Ecore_Animator *)l; - l = l->next; - if (!animator->delete_me) - { - if (!animator->func(animator->data)) - { - animator->delete_me = 1; - animators_delete_me++; - } - } + ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR, + "ecore_animator_del"); + goto unlock; } - if (animators_delete_me) + 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) { - for (l = (Ecore_List2 *)animators; l;) - { - Ecore_Animator *animator; - - animator = (Ecore_Animator *)l; - l = l->next; - if (animator->delete_me) - { - animators = _ecore_list2_remove(animators, animator); - ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE); - free(animator); - animators_delete_me--; - if (animators_delete_me == 0) break; - } - } + 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); } - if (!animators) +} + +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) { - timer = NULL; - return 0; + pos = (t - animator->start) / animator->run; + if (pos > 1.0) pos = 1.0; + else if (pos < 0.0) + pos = 0.0; } - return 1; + 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 index 5f11809..6e73da0 100644 --- a/src/lib/ecore/ecore_app.c +++ b/src/lib/ecore/ecore_app.c @@ -1,20 +1,45 @@ -#include "ecore_private.h" +#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) +ecore_app_args_set(int argc, + const char **argv) { + EINA_MAIN_LOOP_CHECK_RETURN; + if ((argc < 1) || (!argv)) return; app_argc = argc; @@ -25,7 +50,7 @@ ecore_app_args_set(int argc, const 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 @@ -33,15 +58,18 @@ ecore_app_args_set(int argc, const char **argv) * same set by ecore_app_args_set(). */ EAPI void -ecore_app_args_get(int *argc, char ***argv) +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, @@ -50,12 +78,19 @@ ecore_app_args_get(int *argc, char ***argv) 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 index c33b244..bbfa7a9 100644 --- a/src/lib/ecore/ecore_events.c +++ b/src/lib/ecore/ecore_events.c @@ -1,350 +1,386 @@ -#include "ecore_private.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + #include "Ecore.h" +#include "ecore_private.h" -static int events_num = 0; -static Ecore_Event *events = NULL; +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 int event_handlers_num = 0; -static int event_handlers_alloc_num = 0; -static Ecore_List2_Data *event_handlers_delete_list = NULL; - -static Ecore_Event_Filter *event_filters = 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; - - -/** - * 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 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 iteger 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_RENEW), It will keep being called as per normal, for - * each handler set up for that event type. If it returns 0 (or - * ECORE_CALLBACK_CANCEL), 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. - */ +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, int (*func) (void *data, int type, void *event), const void *data) +ecore_event_handler_add(int type, + Ecore_Event_Handler_Cb func, + const void *data) { - Ecore_Event_Handler *eh; + Ecore_Event_Handler *eh = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); - if (!func) return NULL; - if ((type <= ECORE_EVENT_NONE) || (type >= event_id_max)) return NULL; - eh = calloc(1, sizeof(Ecore_Event_Handler)); - if (!eh) return NULL; + 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) - { - free(eh); - return NULL; - } - event_handlers = new_handlers; - for (i = p_alloc_num; i < event_handlers_alloc_num; i++) - event_handlers[i] = NULL; - } + 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; + } } - event_handlers[type] = _ecore_list2_append(event_handlers[type], eh); + 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; } -/** - * 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 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) { - Ecore_List2_Data *node; - - if (!ECORE_MAGIC_CHECK(event_handler, ECORE_MAGIC_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"); - return NULL; + ECORE_MAGIC_FAIL(event_handler, ECORE_MAGIC_EVENT_HANDLER, + "ecore_event_handler_del"); + goto unlock; } - event_handler->delete_me = 1; - node = calloc(1, sizeof(Ecore_List2_Data)); - node->data = event_handler; - event_handlers_delete_list = _ecore_list2_append(event_handlers_delete_list, node); - return event_handler->data; + 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; } -static void -_ecore_event_generic_free (void *data __UNUSED__, void *event) +EAPI void * +ecore_event_handler_data_set(Ecore_Event_Handler *eh, + const void *data) { - free (event); + 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); } -/** - * Add an event to the event queue. - * @param type The event type to add to the end of the event queue - * @param ev The private data structure for this event type - * @param func_free The function to be called to free this private structure - * @param data The data pointer to be passed to the free function - * @return A Handle for that event - * - * On success this function returns a handle to an event on the event queue, or - * NULL if it fails. If it succeeds, an event of type @p type will be added - * to the queue for processing by event handlers added by - * ecore_event_handler_add(). The @p ev parameter will be a pointer to the event - * private data that is specific to that event type. When the event is no - * longer needed, @p func_free will be called and passed the private structure - * pointer for cleaning up. If @p func_free is NULL, free() will be called - * with the private structure pointer. - * func_free is passed @p data as its data parameter. - */ EAPI Ecore_Event * -ecore_event_add(int type, void *ev, void (*func_free) (void *data, void *ev), void *data) +ecore_event_add(int type, + void *ev, + Ecore_End_Cb func_free, + void *data) { -/* if (!ev) return NULL;*/ - if (type <= ECORE_EVENT_NONE) return NULL; - if (type >= event_id_max) return NULL; + 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; - return _ecore_event_add(type, ev, func_free, data); + event = _ecore_event_add(type, ev, func_free, data); +unlock: + _ecore_unlock(); + return event; } -/** - * 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 parameer 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) { - if (!ECORE_MAGIC_CHECK(event, ECORE_MAGIC_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"); - return NULL; + 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; - return event->data; + data = event->data; +unlock: + _ecore_unlock(); + return data; } -/** - * 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) { - event_id_max++; - return event_id_max - 1; + int id; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); + _ecore_lock(); + id = event_id_max++; + _ecore_unlock(); + + return id; } -/** - * 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 queu has been filtered - * @param data Data to pass to the filter functions - * @return A filter handle - * - * This adds a filter to call callbacks to loop through the event queue and - * filter events out of the queue. On failure NULL is returned. On success a - * Filter handle is returned. Filters are called on the queue just before - * Event handler processing to try and remove redundant events. Just as - * processing starts @p func_start is called and passed the @p data pointer. - * This function returns a pointer that is used as loop_data that is now passed to - * @p func_filter as loop_data. @p func_filter is also passed @p data and the - * event type and private event structure. If this callback returns 0, the - * event is removed from the queue. If it returns 1, the event is kept. When - * processing is finished @p func_end is called and is passed the loop_data - * and @p data pointer to clean up. - */ EAPI Ecore_Event_Filter * -ecore_event_filter_add(void * (*func_start) (void *data), int (*func_filter) (void *data, void *loop_data, int type, void *event), void (*func_end) (void *data, void *loop_data), const void *data) +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; - - if (!func_filter) return NULL; - ef = calloc(1, sizeof(Ecore_Event_Filter)); - if (!ef) return NULL; + 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_list2_append(event_filters, ef); + event_filters = (Ecore_Event_Filter *)eina_inlist_append(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef)); +unlock: + _ecore_unlock(); return ef; } -/** - * Delete an event filter. - * @param ef The event filter handle - * @return The data set for the filter - * - * Delete a filter that has been added by its @p ef handle. On success this - * will return the data pointer set when this filter was added. On failure - * NULL is returned. - */ 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"); - return NULL; + 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; - return ef->data; + data = ef->data; +unlock: + _ecore_unlock(); + + return data; } -/** - * Return the current event type being handled. - * @return The current event type being handled if inside a handler callback - * - * If the program is currently inside an Ecore event handler callback this - * will return the type of the current event being processed. If Ecore is - * not inside an event handler, ECORE_EVENT_NONE is returned. - * - * 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) { + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0); return ecore_raw_event_type; } -/** - * Return the current event type pointer handled. - * @return The current event pointer being handled if inside a handler callback - * - * If the program is currently inside an Ecore event handler callback this - * will return the pointer of the current event being processed. If Ecore is - * not inside an event handler, NULL will be returned. - * - * 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) { + 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 (event_handlers[i]) - { - Ecore_Event_Handler *eh; - - eh = event_handlers[i]; - event_handlers[i] = _ecore_list2_remove(event_handlers[i], eh); - ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE); - free(eh); - } - } - while (event_handlers_delete_list) - { - Ecore_List2_Data *ehd; - - ehd = event_handlers_delete_list; - event_handlers_delete_list = _ecore_list2_remove(event_handlers_delete_list, ehd); - free(ehd); + 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 (event_filters) + while ((ef = event_filters)) { - Ecore_Event_Filter *ef; - - ef = event_filters; - event_filters = _ecore_list2_remove(event_filters, ef); - ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE); - free(ef); + 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) { - if (events) return 1; + 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, void (*func_free) (void *data, void *ev), void *data) +_ecore_event_add(int type, + void *ev, + Ecore_End_Cb func_free, + void *data) { Ecore_Event *e; - - e = calloc(1, sizeof(Ecore_Event)); + + 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; - events = _ecore_list2_append(events, e); - events_num++; + 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; } @@ -352,113 +388,227 @@ void * _ecore_event_del(Ecore_Event *event) { void *data; - + data = event->data; - if (event->func_free) event->func_free(event->data, event->event); - events = _ecore_list2_remove(events, event); + 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); - free(event); + ecore_event_mp_free(event); events_num--; return data; } -void -_ecore_event_call(void) +static void +_ecore_event_purge_deleted(void) { - Ecore_List2 *l, *ll; - Ecore_Event *e; - Ecore_Event_Filter *ef; - Ecore_Event_Handler *eh; - Ecore_List2_Data *ehd; - int handle_count; + Ecore_Event *itr = events; - for (l = (Ecore_List2 *)event_filters; l; l = l->next) + inpurge++; + while (itr) { - ef = (Ecore_Event_Filter *)l; - if (!ef->delete_me) - { - if (ef->func_start) - ef->loop_data = ef->func_start(ef->data); - for (ll = (Ecore_List2 *)events; ll; ll = ll->next) - { - e = (Ecore_Event *)ll; - if (!ef->func_filter(ef->loop_data, ef->data, - e->type, e->event)) - { -// printf("FILTER SAID TO DEL ev %p\n", e->event); - ecore_event_del(e); - } - } - if (ef->func_end) - ef->func_end(ef->data, ef->loop_data); - } + 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) { - for (l = (Ecore_List2 *)event_filters; l;) - { - ef = (Ecore_Event_Filter *)l; - l = l->next; - if (ef->delete_me) - { - event_filters = _ecore_list2_remove(event_filters, ef); - ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE); - free(ef); - } - } - event_filters_delete_me = 0; + 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; } -// printf("EVENT BATCH...\n"); - for (l = (Ecore_List2 *)events; l; l = l->next) +} + +void +_ecore_event_call(void) +{ + Eina_List *l, *l_next; + Ecore_Event_Handler *eh; + + _ecore_event_filters_apply(); + + if (!event_current) { - e = (Ecore_Event *)l; - if (!e->delete_me) - { - handle_count = 0; - ecore_raw_event_type = e->type; - ecore_raw_event_event = e->event; -// printf("HANDLE ev type %i, %p\n", e->type, e->event); - if ((e->type >= 0) && (e->type < event_handlers_num)) - { - for (ll = (Ecore_List2 *)event_handlers[e->type]; ll; ll = ll->next) - { - eh = (Ecore_Event_Handler *)ll; - if (!eh->delete_me) - { - handle_count++; - if (!eh->func(eh->data, e->type, e->event)) - break; /* 0 == "call no further handlers" */ - } - } - } - /* 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(); - } + /* regular main loop, start from head */ + event_current = events; + event_handler_current = NULL; } -// printf("EVENT BATCH DONE\n"); + + 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; - - while (events) _ecore_event_del(events); - while (event_handlers_delete_list) + + _ecore_event_purge_deleted(); + + EINA_LIST_FOREACH_SAFE(event_handlers_delete_list, l, l_next, eh) { - ehd = event_handlers_delete_list; - eh = ehd->data; - event_handlers[eh->type] = _ecore_list2_remove(event_handlers[eh->type], eh); - event_handlers_delete_list = _ecore_list2_remove(event_handlers_delete_list, ehd); - ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE); - free(eh); - free(ehd); + 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); } } -EAPI void * +void * _ecore_event_signal_user_new(void) { Ecore_Event_Signal_User *e; - + e = calloc(1, sizeof(Ecore_Event_Signal_User)); return e; } @@ -467,7 +617,7 @@ void * _ecore_event_signal_hup_new(void) { Ecore_Event_Signal_Hup *e; - + e = calloc(1, sizeof(Ecore_Event_Signal_Hup)); return e; } @@ -476,7 +626,7 @@ void * _ecore_event_signal_exit_new(void) { Ecore_Event_Signal_Exit *e; - + e = calloc(1, sizeof(Ecore_Event_Signal_Exit)); return e; } @@ -485,7 +635,7 @@ void * _ecore_event_signal_power_new(void) { Ecore_Event_Signal_Power *e; - + e = calloc(1, sizeof(Ecore_Event_Signal_Power)); return e; } @@ -495,3 +645,4 @@ _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 index ed32bce..7cc4b0f 100644 --- a/src/lib/ecore/ecore_exe.c +++ b/src/lib/ecore/ecore_exe.c @@ -1,11 +1,124 @@ +#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 /* HAVE_SYS_WAIT_H */ -#include "ecore_private.h" +#endif + #include "Ecore.h" +#include "ecore_private.h" -#ifndef _WIN32 +/* 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 - * @@ -16,70 +129,72 @@ * 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 preceeding space. The first is the command off course. + * appended with a preceding space. The first is the command off course. */ struct _ecore_exe_dead_exe { - pid_t pid; - char *cmd; + pid_t pid; + char *cmd; }; -static inline void _ecore_exe_exec_it(const char *exe_cmd, Ecore_Exe_Flags flags); - -static int _ecore_exe_data_generic_handler(void *data, - Ecore_Fd_Handler * - fd_handler, - Ecore_Exe_Flags flags); -static int _ecore_exe_data_error_handler(void *data, - Ecore_Fd_Handler * - fd_handler); -static int _ecore_exe_data_read_handler(void *data, - Ecore_Fd_Handler * fd_handler); -static int _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 int _ecore_exe_make_sure_its_dead(void *data); -static int _ecore_exe_make_sure_its_really_dead(void *data); +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); +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; +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; +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); +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_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) + 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__))) + if (((ok) = _ecore_exe_check_errno((result) = (foo), __FILE__, __LINE__))) static int -_ecore_exe_check_errno(int result, const char *file, int line) +_ecore_exe_check_errno(int result, + const char *file __UNUSED__, + int line __UNUSED__) { - int saved_errno = errno; + int saved_errno = errno; if (result == -1) - { - perror("*** errno reports "); + { + perror("*** errno reports "); /* What is currently supported - * * pipe @@ -135,120 +250,136 @@ _ecore_exe_check_errno(int result, const char *file, int line) * // Something failed, cleanup. * } */ - switch (saved_errno) - { - case EACCES: - case EAGAIN: - case EINTR: - { /* Not now, try later. */ - fprintf(stderr, "*** Must try again in %s @%u.\n", file, line); - result = -1; - break; - } - - case EMFILE: - case ENFILE: - case ENOLCK: - { /* Low on resources. */ - fprintf(stderr, "*** Low on resources in %s @%u.\n", file, - line); - result = 0; - break; - } - - case EIO: - { /* I/O error. */ - fprintf(stderr, "*** I/O error in %s @%u.\n", file, line); - result = 0; - break; - } - - case EFAULT: - case EBADF: - case EINVAL: - case EROFS: - case EISDIR: - case EDEADLK: - case EPERM: - case EBUSY: - { /* Programmer fucked up. */ - fprintf(stderr, - "*** NAUGHTY PROGRAMMER!!!\n" - "*** SPANK SPANK SPANK!!!\n" - "*** Now go fix your code in %s @%u. Tut tut tut!\n" - "\n", file, line); - result = 0; - break; - } - - default: - { /* Unsupported errno code, please add this one. */ - fprintf(stderr, - "*** 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!\n" - "\n", saved_errno, __FILE__, __LINE__, file, line); - result = 0; - break; - } - } - } - else /* Everything is fine. */ - result = 1; + 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; } /** - * @defgroup Ecore_Exe_Basic_Group Process Spawning Functions + * @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. * - * Functions that deal with spawned processes. + * @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. - * @ingroup Ecore_Exe_Basic_Group */ -EAPI Ecore_Exe * -ecore_exe_run(const char *exe_cmd, const void *data) +EAPI Ecore_Exe * +ecore_exe_run(const char *exe_cmd, + const void *data) { -/* I'm just being paranoid again, leaving in the original code in case there is a problem. */ -#if 0 - Ecore_Exe *exe; - pid_t pid; - - if (!exe_cmd) - return NULL; - pid = fork(); - if (pid) - { - exe = calloc(1, sizeof(Ecore_Exe)); - if (!exe) - { - kill(pid, SIGKILL); - return NULL; - } - ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); - exe->pid = pid; - exe->data = (void *)data; - exe->cmd = strdup(exe_cmd); - exes = _ecore_list2_append(exes, exe); - return exe; - } - _ecore_exe_exec_it(exe_cmd, 0); - exit(127); - return NULL; -#else + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); return ecore_exe_pipe_run(exe_cmd, 0, data); -#endif } /** @@ -275,28 +406,30 @@ ecore_exe_run(const char *exe_cmd, const void *data) * @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. - * @ingroup Ecore_Exe_Basic_Group */ -EAPI Ecore_Exe * -ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) +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; - + 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 == NULL) return NULL; + 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; + flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR; exe->child_fd_error = -1; exe->child_fd_read = -1; @@ -307,252 +440,298 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) /* Create some pipes. */ if (ok) - { - E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), 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]; - } - } + { + 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]; - } - } + { + 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]; - } - } + { + 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) - { - fprintf(stderr, "Failed to fork process\n"); - pid = 0; - } - else if (pid == 0) /* child */ - { - /* 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 sucess */ - { - /* 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; - fprintf(stderr, "Could not start \"%s\"\n", - 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 == NULL) - 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 == NULL) - 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_list2_append(exes, 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); - } + { + 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); - /* printf("Running as %d for %s.\n", exe->pid, exe->cmd); */ - } - + { + 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; } /** - * Sends data to the given child process which it recieves on stdin. + * 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 @@ -561,63 +740,89 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) * @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 1 if successful, 0 on failure. - * @ingroup Ecore_Exe_Basic_Group + * @return @c EINA_TRUE if successful, @c EINA_FALSE on failure. */ -EAPI int -ecore_exe_send(Ecore_Exe * exe, void *data, int size) +EAPI Eina_Bool +ecore_exe_send(Ecore_Exe *exe, + const void *data, + int size) { - void *buf; + 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 == NULL) return 0; + 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); + ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE); - return 1; + return EINA_TRUE; } /** * The stdin of the given child process will close when the write buffer is empty. * * @param exe The child process - * @ingroup Ecore_Exe_Basic_Group */ EAPI void -ecore_exe_close_stdin(Ecore_Exe * exe) +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; - } + { + 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 + * 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. - * @ingroup Ecore_Exe_Basic_Group */ EAPI void -ecore_exe_auto_limits_set(Ecore_Exe * exe, int start_bytes, int end_bytes, - int start_lines, int end_lines) +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; - } + { + 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; @@ -658,7 +863,7 @@ ecore_exe_auto_limits_set(Ecore_Exe * exe, int start_bytes, int end_bytes, * 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 seperate out/err limits? + * 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. */ @@ -669,129 +874,130 @@ ecore_exe_auto_limits_set(Ecore_Exe * exe, int start_bytes, int end_bytes, * * @param exe The given process handle. * @param flags Is this a ECORE_EXE_PIPE_READ or ECORE_EXE_PIPE_ERROR? - * @ingroup Ecore_Exe_Basic_Group + * @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_get(Ecore_Exe *exe, + Ecore_Exe_Flags flags) { Ecore_Exe_Event_Data *e = NULL; - int is_buffered = 0; - unsigned char *inbuf; - int inbuf_num; + 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; - } + { + 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; - } + { + 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; - } + { + 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; - } + { + 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; - } + { + 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 (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; - } - if (i > last) /* Partial line left over, save it for next time. */ - { - if (e) - 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); - } - } - } - } + { + 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; } @@ -801,19 +1007,22 @@ ecore_exe_event_data_get(Ecore_Exe * exe, Ecore_Exe_Flags flags) * * @param exe The given process handle. * @param tag The string tag to set on the process handle. - * @ingroup Ecore_Exe_Basic_Group */ EAPI void -ecore_exe_tag_set(Ecore_Exe * exe, const char *tag) +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; - } + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set"); + return; + } IF_FREE(exe->tag); if (tag) - exe->tag = strdup(tag); + exe->tag = strdup(tag); + else + exe->tag = NULL; } /** @@ -823,17 +1032,19 @@ ecore_exe_tag_set(Ecore_Exe * exe, const char *tag) * else on this @p exe. * * @param exe The given process handle. - * @return The string attached to @p exe. - * @ingroup Ecore_Exe_Basic_Group + * @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 char * -ecore_exe_tag_get(Ecore_Exe * exe) +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; - } + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get"); + return NULL; + } return exe->tag; } @@ -846,58 +1057,61 @@ ecore_exe_tag_get(Ecore_Exe * exe) * @param exe The given process handle. * @return The data attached to the handle when @ref ecore_exe_run was * called. - * @ingroup Ecore_Exe_Basic_Group */ -EAPI void * -ecore_exe_free(Ecore_Exe * exe) +EAPI void * +ecore_exe_free(Ecore_Exe *exe) { - void *data; - int ok = 0; - int result; + 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; - } + { + 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; - } - } + { + 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); + 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); + 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); + 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); + 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); + 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); + 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_list2_remove(exes, exe); + 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); @@ -908,11 +1122,11 @@ ecore_exe_free(Ecore_Exe * exe) * Frees the given event data. * * @param e The given event data. - * @ingroup Ecore_Exe_Basic_Group */ EAPI void -ecore_exe_event_data_free(Ecore_Exe_Event_Data * e) +ecore_exe_event_data_free(Ecore_Exe_Event_Data *e) { + if (!e) return; IF_FREE(e->lines); IF_FREE(e->data); free(e); @@ -922,104 +1136,142 @@ ecore_exe_event_data_free(Ecore_Exe_Event_Data * 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. - * @ingroup Ecore_Exe_Basic_Group */ -EAPI pid_t -ecore_exe_pid_get(Ecore_Exe * exe) +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; - } + { + 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. NULL otherwise. - * @ingroup Ecore_Exe_Basic_Group + * @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 char * -ecore_exe_cmd_get(Ecore_Exe * exe) +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; - } + { + 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. - * @ingroup Ecore_Exe_Basic_Group + * @return The data pointer attached to @p exe Given to + * ecore_exe_run() or ecore_exe_pipe_run() */ -EAPI void * -ecore_exe_data_get(Ecore_Exe * exe) +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; - } + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get"); + return NULL; + } return exe->data; } /** - * @defgroup Ecore_Exe_Signal_Group Spawned Process Signal Functions - * - * Functions that send signals to spawned processes. + * 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. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_pause(Ecore_Exe * exe) +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; - } + { + 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. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_continue(Ecore_Exe * exe) +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; - } + { + 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. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_interrupt(Ecore_Exe * exe) +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_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt"); + return; + } _ecore_exe_dead_attach(exe); kill(exe->pid, SIGINT); } @@ -1027,16 +1279,16 @@ ecore_exe_interrupt(Ecore_Exe * exe) /** * Sends the given spawned process a quit (@c SIGQUIT) signal. * @param exe Process handle to the given process. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_quit(Ecore_Exe * exe) +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_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit"); + return; + } _ecore_exe_dead_attach(exe); kill(exe->pid, SIGQUIT); } @@ -1044,48 +1296,48 @@ ecore_exe_quit(Ecore_Exe * exe) /** * Sends the given spawned process a terminate (@c SIGTERM) signal. * @param exe Process handle to the given process. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_terminate(Ecore_Exe * exe) +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_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate"); + return; + } _ecore_exe_dead_attach(exe); - printf("Sending TERM signal to %s (%d).\n", exe->cmd, exe->pid); + 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. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_kill(Ecore_Exe * exe) +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; - } + { + 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); - } - - printf("Sending KILL signal to %s (%d).\n", exe->cmd, exe->pid); + { + 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); } @@ -1094,44 +1346,49 @@ ecore_exe_kill(Ecore_Exe * exe) * @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. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_signal(Ecore_Exe * exe, int num) +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; - } + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal"); + return; + } if (num == 1) - kill(exe->pid, SIGUSR1); + kill(exe->pid, SIGUSR1); else if (num == 2) - kill(exe->pid, SIGUSR2); + kill(exe->pid, SIGUSR2); } /** * Sends a @c SIGHUP signal to the given spawned process. * @param exe Process handle to the given process. - * @ingroup Ecore_Exe_Signal_Group */ EAPI void -ecore_exe_hup(Ecore_Exe * exe) +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; - } + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup"); + return; + } kill(exe->pid, SIGHUP); } -static Ecore_Exe * +/** + * @} + */ + +static Ecore_Exe * _ecore_exe_is_it_alive(pid_t pid) { - Ecore_Exe *exe = NULL; + Ecore_Exe *exe = NULL; - /* FIXME: There is no nice, safe, OS independant way to tell if a + /* 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. @@ -1155,70 +1412,69 @@ _ecore_exe_is_it_alive(pid_t pid) */ exe = _ecore_exe_find(pid); if (exe) - { - if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) - exe = NULL; - } + { + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + exe = NULL; + } return exe; } -static int +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)) != NULL) - { - if (dead->cmd) - printf("Sending KILL signal to alledgedly dead %s (%d).\n", - dead->cmd, dead->pid); - else - printf("Sending KILL signal to alledgedly dead PID %d.\n", - 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 0; + { + 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 int +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)) != NULL) - { - printf - ("RUN! The zombie wants to eat your brains! And your CPU!\n"); - if (dead->cmd) - printf("%s (%d) is not really dead.\n", dead->cmd, dead->pid); - else - printf("PID %d is not really dead.\n", dead->pid); - exe->doomsday_clock = NULL; - } - IF_FREE(dead->cmd); - free(dead); - } - return 0; + { + 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 @@ -1234,32 +1490,43 @@ void _ecore_exe_shutdown(void) { while (exes) - ecore_exe_free(exes); + ecore_exe_free(exes); } -Ecore_Exe * +Ecore_Exe * _ecore_exe_find(pid_t pid) { - Ecore_List2 *l; - - for (l = (Ecore_List2 *) exes; l; l = l->next) - { - Ecore_Exe *exe; + Ecore_Exe *exe; - exe = (Ecore_Exe *) l; - if (exe->pid == pid) - return 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) +_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; + char use_sh = 1; + char *buf = NULL; + char **args = NULL; + int save_errno = 0; /* So what is this doing? * @@ -1268,78 +1535,92 @@ _ecore_exe_exec_it(const char *exe_cmd, Ecore_Exe_Flags flags) * 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; - } - } + { + 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 == NULL) - { /* Find users preferred shell. */ - shell = getenv("SHELL"); - if (shell == 0) - shell = "/bin/sh"; - } - errno = 0; - execl(shell, shell, "-c", exe_cmd, (char *)NULL); - } + { + 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. */ - errno = 0; - execvp(args[0], args); - } + { /* 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); @@ -1348,226 +1629,223 @@ _ecore_exe_exec_it(const char *exe_cmd, Ecore_Exe_Flags flags) return; } -static int -_ecore_exe_data_generic_handler(void *data, Ecore_Fd_Handler * fd_handler, - Ecore_Exe_Flags flags) +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 is_buffered = 0; - int event_type; + 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; - if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED) - is_buffered = 1; - } + { + 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 (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED) - is_buffered = 1; - } + { + 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) - printf - ("There are %d bytes left unsent from the dead exe %s.\n", - exe->read_data_size, exe->cmd); - } - else - { - if (exe->error_data_size) - printf - ("There are %d bytes left unsent from the dead exe %s.\n", - 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 1; + { + 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 int -_ecore_exe_data_error_handler(void *data, Ecore_Fd_Handler * fd_handler) +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); + ECORE_EXE_PIPE_ERROR); } -static int -_ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler * fd_handler) +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); + ECORE_EXE_PIPE_READ); } -static int -_ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler * fd_handler __UNUSED__) +static Eina_Bool +_ecore_exe_data_write_handler(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) { - Ecore_Exe *exe; + Ecore_Exe *exe; exe = data; - if ((exe->write_fd_handler) - && + if ((exe->write_fd_handler) && (ecore_main_fd_handler_active_get - (exe->write_fd_handler, ECORE_FD_WRITE))) - _ecore_exe_flush(exe); + (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; - - printf("Closing stdin for %s\n", 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 1; + { + 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) +_ecore_exe_flush(Ecore_Exe *exe) { - int count; + int count; /* check whether we need to write anything at all. */ if ((exe->child_fd_write == -1) || (!exe->write_data_buf)) - return; + return; if (exe->write_data_size == exe->write_data_offset) - return; + return; count = write(exe->child_fd_write, - (char *)exe->write_data_buf + exe->write_data_offset, - exe->write_data_size - exe->write_data_offset); + (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); - } - } + { + 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); - } - } + { + 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_exe_data_free(void *data __UNUSED__, + void *ev) { Ecore_Exe_Event_Data *e; @@ -1585,7 +1863,8 @@ _ecore_exe_event_add_new(void) } static void -_ecore_exe_event_add_free(void *data __UNUSED__, void *ev) +_ecore_exe_event_add_free(void *data __UNUSED__, + void *ev) { Ecore_Exe_Event_Add *e; @@ -1593,7 +1872,7 @@ _ecore_exe_event_add_free(void *data __UNUSED__, void *ev) free(e); } -void * +void * _ecore_exe_event_del_new(void) { Ecore_Exe_Event_Del *e; @@ -1603,13 +1882,14 @@ _ecore_exe_event_del_new(void) } void -_ecore_exe_event_del_free(void *data __UNUSED__, void *ev) +_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); + ecore_exe_free(e->exe); free(e); } @@ -1621,14 +1901,13 @@ _ecore_exe_dead_attach(Ecore_Exe *exe) 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; - } + { + 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; + } } -#endif 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 index 7c9d03f..73e72cb 100644 --- a/src/lib/ecore/ecore_idle_enterer.c +++ b/src/lib/ecore/ecore_idle_enterer.c @@ -1,8 +1,35 @@ -#include "ecore_private.h" +#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 int idle_enterers_delete_me = 0; +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. @@ -10,20 +37,28 @@ static int idle_enterers_delete_me = 0; * @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. - * @ingroup Idle_Group + * @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(int (*func) (void *data), const void *data) +ecore_idle_enterer_add(Ecore_Task_Cb func, + const void *data) { - Ecore_Idle_Enterer *ie; + Ecore_Idle_Enterer *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); - if (!func) return NULL; - ie = calloc(1, sizeof(Ecore_Idle_Enterer)); - if (!ie) return NULL; + 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_list2_append(idle_enterers, ie); + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); return ie; } @@ -33,20 +68,28 @@ ecore_idle_enterer_add(int (*func) (void *data), const void *data) * @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. - * @ingroup Idle_Group + * @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(int (*func) (void *data), const void *data) +ecore_idle_enterer_before_add(Ecore_Task_Cb func, + const void *data) { - Ecore_Idle_Enterer *ie; + Ecore_Idle_Enterer *ie = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); - if (!func) return NULL; - ie = calloc(1, sizeof(Ecore_Idle_Enterer)); - if (!ie) return NULL; + 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_list2_prepend(idle_enterers, ie); + idle_enterers = (Ecore_Idle_Enterer *)eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); return ie; } @@ -55,17 +98,33 @@ ecore_idle_enterer_before_add(int (*func) (void *data), const void *data) * @param idle_enterer The idle enterer to delete * @return The data pointer passed to the idler enterer callback on success. * NULL otherwise. - * @ingroup Idle_Group */ 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_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; @@ -74,49 +133,72 @@ ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer) void _ecore_idle_enterer_shutdown(void) { - while (idle_enterers) + Ecore_Idle_Enterer *ie; + while ((ie = idle_enterers)) { - Ecore_Idle_Enterer *ie; - - ie = idle_enterers; - idle_enterers = _ecore_list2_remove(idle_enterers, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); + 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) { - Ecore_List2 *l; - - for (l = (Ecore_List2 *)idle_enterers; l; l = l->next) + if (!idle_enterer_current) { - Ecore_Idle_Enterer *ie; - - ie = (Ecore_Idle_Enterer *)l; - if (!ie->delete_me) - { - if (!ie->func(ie->data)) ecore_idle_enterer_del(ie); - } + /* 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) { - for (l = (Ecore_List2 *)idle_enterers; l;) - { - Ecore_Idle_Enterer *ie; - - ie = (Ecore_Idle_Enterer *)l; - l = l->next; - if (ie->delete_me) - { - idle_enterers = _ecore_list2_remove(idle_enterers, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); - } - } - idle_enterers_delete_me = 0; + 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; } } @@ -126,3 +208,4 @@ _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 index b9d4128..0086bb6 100644 --- a/src/lib/ecore/ecore_idle_exiter.c +++ b/src/lib/ecore/ecore_idle_exiter.c @@ -1,28 +1,62 @@ -#include "ecore_private.h" +#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 int idle_exiters_delete_me = 0; +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. - * @ingroup Idle_Group + * @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(int (*func) (void *data), const void *data) +ecore_idle_exiter_add(Ecore_Task_Cb func, + const void *data) { - Ecore_Idle_Exiter *ie; + Ecore_Idle_Exiter *ie = NULL; - if (!func) return NULL; - ie = calloc(1, sizeof(Ecore_Idle_Exiter)); - if (!ie) return 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_list2_append(idle_exiters, ie); + idle_exiters = (Ecore_Idle_Exiter *)eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); return ie; } @@ -31,17 +65,33 @@ ecore_idle_exiter_add(int (*func) (void *data), const void *data) * @param idle_exiter The idle exiter to delete * @return The data pointer that was being being passed to the handler if * successful. NULL otherwise. - * @ingroup Idle_Group */ 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_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; @@ -50,49 +100,73 @@ ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter) void _ecore_idle_exiter_shutdown(void) { - while (idle_exiters) + Ecore_Idle_Exiter *ie; + while ((ie = idle_exiters)) { - Ecore_Idle_Exiter *ie; - - ie = idle_exiters; - idle_exiters = _ecore_list2_remove(idle_exiters, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); + 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) { - Ecore_List2 *l; - - for (l = (Ecore_List2 *)idle_exiters; l; l = l->next) + if (!idle_exiter_current) + { + /* regular main loop, start from head */ + idle_exiter_current = idle_exiters; + } + else { - Ecore_Idle_Exiter *ie; - - ie = (Ecore_Idle_Exiter *)l; - if (!ie->delete_me) - { - if (!ie->func(ie->data)) ecore_idle_exiter_del(ie); - } + /* 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) { - for (l = (Ecore_List2 *)idle_exiters; l;) - { - Ecore_Idle_Exiter *ie; - - ie = (Ecore_Idle_Exiter *)l; - l = l->next; - if (ie->delete_me) - { - idle_exiters = _ecore_list2_remove(idle_exiters, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); - } - } - idle_exiters_delete_me = 0; + 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; } } @@ -102,3 +176,4 @@ _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 index ff2dd7e..62998b6 100644 --- a/src/lib/ecore/ecore_idler.c +++ b/src/lib/ecore/ecore_idler.c @@ -1,55 +1,81 @@ -#include "ecore_private.h" +#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 int idlers_delete_me = 0; +static Ecore_Idler *idler_current = NULL; +static int idlers_delete_me = 0; + +static void * +_ecore_idler_del(Ecore_Idler *idler); -/** - * 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. NULL otherwise. - * @ingroup Idle_Group - * - * Add an idler handle to the event loop, returning a handle on success and - * NULL otherwise. The function @p func will be called repeatedly while - * no other events are ready to be processed, as long as it returns 1 - * (or ECORE_CALLBACK_RENEW). A return of 0 (or ECORE_CALLBACK_CANCEL) deletes - * the idler. - * - * Idlers are useful for progressively prossessing data without blocking. - */ EAPI Ecore_Idler * -ecore_idler_add(int (*func) (void *data), const void *data) +ecore_idler_add(Ecore_Task_Cb func, + const void *data) { - Ecore_Idler *ie; + Ecore_Idler *ie = NULL; - if (!func) return NULL; - ie = calloc(1, sizeof(Ecore_Idler)); - if (!ie) return 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_list2_append(idlers, ie); + idlers = (Ecore_Idler *)eina_inlist_append(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie)); +unlock: + _ecore_unlock(); return ie; } -/** - * 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. NULL - * otherwise. - * @ingroup Idle_Group - */ 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_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; @@ -58,49 +84,69 @@ ecore_idler_del(Ecore_Idler *idler) void _ecore_idler_shutdown(void) { - while (idlers) + Ecore_Idler *ie; + while ((ie = idlers)) { - Ecore_Idler *ie; - - ie = idlers; - idlers = _ecore_list2_remove(idlers, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); + 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_call(void) +_ecore_idler_all_call(void) { - Ecore_List2 *l; + 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; + } - for (l = (Ecore_List2 *)idlers; l; l = l->next) + while (idler_current) { - Ecore_Idler *ie; - - ie = (Ecore_Idler *)l; - if (!ie->delete_me) - { - if (!ie->func(ie->data)) ecore_idler_del(ie); - } + 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) { - for (l = (Ecore_List2 *)idlers; l;) - { - Ecore_Idler *ie; - - ie = (Ecore_Idler *)l; - l = l->next; - if (ie->delete_me) - { - idlers = _ecore_list2_remove(idlers, ie); - ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE); - free(ie); - } - } - idlers_delete_me = 0; + 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; @@ -112,3 +158,4 @@ _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 index 4ba6856..a3b4245 100644 --- a/src/lib/ecore/ecore_main.c +++ b/src/lib/ecore/ecore_main.c @@ -1,319 +1,1405 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #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 #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 +//#define FIX_HZ 1 #ifdef FIX_HZ -# include +# ifndef _MSC_VER +# include +# endif # ifndef HZ # define HZ 100 # endif #endif -#include "ecore_private.h" +#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 int in_main_loop = 0; +static int do_quit = 0; static Ecore_Fd_Handler *fd_handlers = NULL; -static int fd_handlers_delete_me = 0; +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 + +Eina_Bool +_ecore_fd_close_on_exec(int fd) +{ +#ifdef HAVE_EXECVP + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + return EINA_FALSE; + + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) + return EINA_FALSE; + return EINA_TRUE; +#else + (void) fd; + return EINA_FALSE; +#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 double t1 = 0.0; -static double t2 = 0.0; +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(); + _ecore_fd_close_on_exec(epoll_fd); + + /* 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_fd_close_on_exec(timer_fd); + 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; +} /** - * @defgroup Ecore_Main_Loop_Group Main Loop Functions - * - * These functions control the Ecore event handling loop. This loop is - * designed to work on embedded systems all the way to large and - * powerful mutli-cpu workstations. - * - * It serialises all system signals and events into a single event - * queue, that can be easily processed without needing to worry about - * concurrency. A properly written, event-driven program using this - * kind of programming does not need threads. It makes the program very - * robust and easy to follow. - * - * Here is an example of simple program and its basic event loop flow: - * @image html prog_flow.png + * @addtogroup Ecore_Main_Loop_Group * - * For examples of setting up and using a main loop, see - * @ref event_handler_example.c and @ref timer_example.c. + * @{ */ /** * Runs a single iteration of the main loop to process everything on the * queue. - * @ingroup Ecore_Main_Loop_Group + * + * 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. + * 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. * - * @ingroup Ecore_Main_Loop_Group + * 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++; - for (;do_quit == 0;) _ecore_main_loop_iterate_internal(0); + _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. - * @ingroup Ecore_Main_Loop_Group + * + * 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 } /** - * @defgroup Ecore_FD_Handler_Group File Event Handling Functions + * 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. * - * Functions that deal with file descriptor handlers. + * 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; +} /** - * Adds a callback for activity on the given file descriptor. - * - * @p func will be called during the execution of @ref ecore_main_loop_begin - * when the file descriptor is available for reading, or writing, or both. - * - * Normally the return value from the @p func is "zero means this handler is - * finished and can be deleted" as is usual for handler callbacks. However, - * if the @p buf_func is supplied, then the return value from the @p func is - * "non zero means the handler should be called again in a tight loop". - * - * @p 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 @p buf_func. - * This is a most annoying hack, only ecore_x uses it, so refer to that for - * an example. NOTE - @p func should probably return "one" always if - * @p buf_func is used, to avoid confusion with the other return value - * semantics. + * Gets the select function set by ecore_select_func_set(), + * or the native select function if none was set. * - * @param fd The file descriptor to watch. - * @param flags To watch it for read (@c ECORE_FD_READ) and/or - * (@c ECORE_FD_WRITE) write ability. @c ECORE_FD_ERROR - * - * @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. Can be @c NULL. - * @param buf_data The data to pass to the @p buf_func function. - * @return A fd handler handle if successful. @c NULL otherwise. - * @ingroup Ecore_FD_Handler_Group */ +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, int (*func) (void *data, Ecore_Fd_Handler *fd_handler), const void *data, int (*buf_func) (void *buf_data, Ecore_Fd_Handler *fd_handler), const void *buf_data) +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; + Ecore_Fd_Handler *fdh = NULL; + + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); - if ((fd < 0) || - (flags == 0) || - (!func)) return NULL; - fdh = calloc(1, sizeof(Ecore_Fd_Handler)); - if (!fdh) return NULL; + 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->read_active = 0; - fdh->write_active = 0; - fdh->error_active = 0; - fdh->delete_me = 0; + 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_list2_append(fd_handlers, fdh); + fd_handlers = (Ecore_Fd_Handler *) + eina_inlist_append(EINA_INLIST_GET(fd_handlers), + EINA_INLIST_GET(fdh)); +unlock: + _ecore_unlock(); + return fdh; } -/** - * Deletes the given FD handler. - * @param fd_handler The given FD handler. - * @return The data pointer set using @ref ecore_main_fd_handler_add, - * for @p fd_handler on success. @c NULL otherwise. - * @ingroup Ecore_FD_Handler_Group - */ +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_fd_handler_del(Ecore_Fd_Handler *fd_handler) +ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler) { - if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER)) + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + if (!ECORE_MAGIC_CHECK(win32_handler, ECORE_MAGIC_WIN32_HANDLER)) { - ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, - "ecore_main_fd_handler_del"); - return NULL; + ECORE_MAGIC_FAIL(win32_handler, ECORE_MAGIC_WIN32_HANDLER, + "ecore_main_win32_handler_del"); + return NULL; } - fd_handler->delete_me = 1; - fd_handlers_delete_me = 1; - return fd_handler->data; + 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, void (*func) (void *data, Ecore_Fd_Handler *fd_handler), const void *data) +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"); - return; + 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; + 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(); } -/** - * 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. - * @ingroup Ecore_FD_Handler_Group - */ 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"); - return -1; + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_fd_get"); + goto unlock; } - return fd_handler->fd; + fd = fd_handler->fd; +unlock: + _ecore_unlock(); + return fd; } -/** - * Return if read, write or error, or a combination thereof, is active on the - * file descriptor of the given 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 1 if any of the given flags are active. @c 0 otherwise. - * @ingroup Ecore_FD_Handler_Group - */ -EAPI int -ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags) +EAPI Eina_Bool +ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, + Ecore_Fd_Handler_Flags flags) { - int ret; + 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"); - return 0; + ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER, + "ecore_main_fd_handler_active_get"); + goto unlock; } - ret = 0; - if ((flags & ECORE_FD_READ) && (fd_handler->read_active)) ret = 1; - if ((flags & ECORE_FD_WRITE) && (fd_handler->write_active)) ret = 1; - if ((flags & ECORE_FD_ERROR) && (fd_handler->error_active)) ret = 1; + 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; } -/** - * 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. - * @ingroup Ecore_FD_Handler_Group - */ EAPI void -ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, Ecore_Fd_Handler_Flags flags) +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"); - return; + 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) { - fprintf(stderr, - "\n" - "*** ECORE WARINING: Calling ecore_shutdown() while still in the main loop.\n" - "*** Program may crash or behave strangely now.\n"); - return; + 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; + 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; - fdh = fd_handlers; - fd_handlers = _ecore_list2_remove(fd_handlers, fdh); - ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE); - free(fdh); + /* 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); } - fd_handlers_delete_me = 0; } +#ifndef USE_G_MAIN_LOOP static int _ecore_main_select(double timeout) { struct timeval tv, *t; - fd_set rfds, wfds, exfds; - int max_fd; - int ret; - Ecore_List2 *l; + fd_set rfds, wfds, exfds; + Ecore_Fd_Handler *fdh; + Eina_List *l; + int max_fd; + int ret; t = NULL; - if ((!finite(timeout)) || (timeout == 0.0)) /* finite() tests for NaN, too big, too small, and infinity. */ + 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; + tv.tv_sec = 0; + tv.tv_usec = 0; + t = &tv; } else if (timeout > 0.0) { - int sec, usec; + int sec, usec; #ifdef FIX_HZ - timeout += (0.5 / HZ); - sec = (int)timeout; - usec = (int)((timeout - (double)sec) * 1000000); + timeout += (0.5 / HZ); + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); #else - sec = (int)timeout; - usec = (int)((timeout - (double)sec) * 1000000); + sec = (int)timeout; + usec = (int)((timeout - (double)sec) * 1000000); #endif - tv.tv_sec = sec; - tv.tv_usec = usec; - t = &tv; + tv.tv_sec = sec; + tv.tv_usec = usec; + t = &tv; } max_fd = 0; FD_ZERO(&rfds); @@ -321,373 +1407,709 @@ _ecore_main_select(double timeout) FD_ZERO(&exfds); /* call the prepare callback for all handlers */ - for (l = (Ecore_List2 *)fd_handlers; l; l = l->next) - { - Ecore_Fd_Handler *fdh; - - fdh = (Ecore_Fd_Handler *)l; + if (fd_handlers_with_prep) + _ecore_main_prepare_handlers(); - if (!fdh->delete_me && fdh->prep_func) - fdh->prep_func (fdh->prep_data, fdh); + 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; + } + } + } } - for (l = (Ecore_List2 *)fd_handlers; l; l = l->next) + else { - Ecore_Fd_Handler *fdh; - - fdh = (Ecore_Fd_Handler *)l; - 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; - } + /* 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; - ret = select(max_fd + 1, &rfds, &wfds, &exfds, t); + + _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) { - if (errno == EINTR) return -1; +#ifndef _WIN32 + if (errno == EINTR) return -1; + else if (errno == EBADF) + _ecore_main_fd_handlers_bads_rem(); +#endif } if (ret > 0) { - for (l = (Ecore_List2 *)fd_handlers; l; l = l->next) - { - Ecore_Fd_Handler *fdh; - - fdh = (Ecore_Fd_Handler *)l; - if (!fdh->delete_me) - { - if (FD_ISSET(fdh->fd, &rfds)) - fdh->read_active = 1; - if (FD_ISSET(fdh->fd, &wfds)) - fdh->write_active = 1; - if (FD_ISSET(fdh->fd, &exfds)) - fdh->error_active = 1; - } - } - _ecore_main_fd_handlers_cleanup(); - return 1; + 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_cleanup(void) +_ecore_main_fd_handlers_bads_rem(void) { - Ecore_List2 *l; + Ecore_Fd_Handler *fdh; + Eina_Inlist *l; + int found = 0; - if (!fd_handlers_delete_me) return; - for (l = (Ecore_List2 *)fd_handlers; l;) + ERR("Removing bad fds"); + for (l = EINA_INLIST_GET(fd_handlers); l; ) { - Ecore_Fd_Handler *fdh; + fdh = (Ecore_Fd_Handler *)l; + l = l->next; + errno = 0; - fdh = (Ecore_Fd_Handler *)l; - l = l->next; - if (fdh->delete_me) - { - fd_handlers = _ecore_list2_remove(fd_handlers, fdh); - ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE); - free(fdh); - } + 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 } - fd_handlers_delete_me = 0; + _ecore_main_fd_handlers_cleanup(); } +# endif +#endif + static void -_ecore_main_fd_handlers_call(void) +_ecore_main_fd_handlers_cleanup(void) { - Ecore_List2 *l; + Ecore_Fd_Handler *fdh; + Eina_List *l, *l2; - for (l = (Ecore_List2 *)fd_handlers; l; l = l->next) + if (!fd_handlers_to_delete) return; + EINA_LIST_FOREACH_SAFE(fd_handlers_to_delete, l, l2, fdh) { - Ecore_Fd_Handler *fdh; - - fdh = (Ecore_Fd_Handler *)l; - if (!fdh->delete_me) - { - if ((fdh->read_active) || - (fdh->write_active) || - (fdh->error_active)) - { - if (!fdh->func(fdh->data, fdh)) - { - fdh->delete_me = 1; - fd_handlers_delete_me = 1; - } - fdh->read_active = 0; - fdh->write_active = 0; - fdh->error_active = 0; - } - } + 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); } } -static int -_ecore_main_fd_handlers_buf_call(void) +#ifdef _WIN32 +static void +_ecore_main_win32_handlers_cleanup(void) { - Ecore_List2 *l; - int ret; + Ecore_Win32_Handler *wh; + Eina_Inlist *l; + int deleted_in_use = 0; - ret = 0; - for (l = (Ecore_List2 *)fd_handlers; l; l = l->next) - { - Ecore_Fd_Handler *fdh; - - fdh = (Ecore_Fd_Handler *)l; - if (!fdh->delete_me) - { - if (fdh->buf_func) - { - if (fdh->buf_func(fdh->buf_data, fdh)) - { - ret |= fdh->func(fdh->data, fdh); - fdh->read_active = 1; - } - } - } + 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); + } } - return ret; + if (!deleted_in_use) win32_handlers_delete_me = EINA_FALSE; } -static int -_ecore_main_win32_message(double timeout) +#endif + +static void +_ecore_main_fd_handlers_call(void) { -#ifdef _WIN32 - MSG msg; + /* grab a new list */ + if (!fd_handlers_to_call_current) + { + fd_handlers_to_call_current = fd_handlers_to_call; + fd_handlers_to_call = NULL; + } - if (!finite(timeout)) - timeout = 0.0; + while (fd_handlers_to_call_current) + { + Ecore_Fd_Handler *fdh = fd_handlers_to_call_current; - if (timeout < 0.0) - { - for (;;) - { - if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) - return 1; - } - } - else - { - double start; - double t; + 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(); - start = ecore_time_get(); - while ((t = ecore_time_get()) < (start + timeout)) - { - if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) - return 1; - } - } -#endif /* _WIN32 */ + fdh->read_active = EINA_FALSE; + fdh->write_active = EINA_FALSE; + fdh->error_active = EINA_FALSE; + } + } - return 0; + /* 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_win32_message_buf_call(void) +_ecore_main_fd_handlers_buf_call(void) { -#ifdef _WIN32 - MSG msg; + Ecore_Fd_Handler *fdh; + Eina_List *l, *l2; int ret; ret = 0; - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + EINA_LIST_FOREACH_SAFE(fd_handlers_with_buffer, l, l2, fdh) { - if ((msg.message & 0xffff) < 0xC000) + if (!fdh) { - TranslateMessage(&msg); - DispatchMessage(&msg); + fd_handlers_with_buffer = eina_list_remove_list(l, fd_handlers_with_buffer); + continue; } - ret = 1; + 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; -#else - return 0; -#endif /* _WIN32 */ +} + +#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; - int have_event = 0; - int have_signal; - int have_msg = 0; + double next_time = -1.0; in_main_loop++; /* expire any timers */ - { - double now; + _ecore_timer_expired_timers_call(_ecore_time_loop_time); + _ecore_timer_cleanup(); - now = ecore_time_get(); - while (_ecore_timer_call(now)); - _ecore_timer_cleanup(); - } - /* any timers re-added as a result of these are allowed to go */ - _ecore_timer_enable_new(); /* process signals into events .... */ - while (_ecore_signal_count_get()) _ecore_signal_call(); + _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()) { - have_event = 1; - have_signal = 1; - have_msg = 1; - _ecore_main_select(0.0); - _ecore_main_win32_message(0.0); - goto process_events; + /* 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; + } } - /* call idle enterers ... */ - if (!once_only) - _ecore_idle_enterer_call(); else { - have_event = have_signal = have_msg = 0; - - if (_ecore_main_select(0.0) > 0) have_event = 1; - - if (_ecore_main_win32_message(0.0) > 0) have_msg = 1; - if (_ecore_signal_count_get() > 0) have_signal = 1; - - if (have_signal || have_event || have_msg) - goto process_events; + /* call idle enterers ... */ + _ecore_idle_enterer_call(); + _ecore_throttle(); } /* if these calls caused any buffered events to appear - deal with them */ - while (_ecore_main_fd_handlers_buf_call()); - while (_ecore_main_win32_message_buf_call()); + if (fd_handlers_with_buffer) + _ecore_main_fd_handlers_buf_call(); - /* if ther are any - jump to processing them */ + /* if there are any (buffered fd handling may generate them) + * then jump to processing them */ if (_ecore_event_exist()) { - have_event = 1; - have_signal = 1; - have_msg = 1; - _ecore_main_select(0.0); - _ecore_main_win32_message(0.0); - goto process_events; + _ecore_main_select(0.0); + _ecore_timer_enable_new(); + goto process_all; } + if (once_only) { - _ecore_idle_enterer_call(); - in_main_loop--; - return; + /* in once_only mode enter idle here instead and then return */ + _ecore_idle_enterer_call(); + _ecore_throttle(); + _ecore_timer_enable_new(); + goto done; } - if (_ecore_fps_debug) - { - t2 = ecore_time_get(); - if ((t1 > 0.0) && (t2 > 0.0)) - _ecore_fps_debug_runtime_add(t2 - t1); - } - start_loop: + _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) { - in_main_loop--; - return; + _ecore_timer_enable_new(); + goto done; } if (!_ecore_event_exist()) { - /* init flags */ - have_event = have_signal = have_msg = 0; - next_time = _ecore_timer_next_get(); - /* no timers */ - if (next_time < 0) - { - /* no idlers */ - if (!_ecore_idler_exist()) - { - if (_ecore_main_select(-1.0) > 0) have_event = 1; - if (_ecore_main_win32_message(-1.0) > 0) have_msg = 1; - if (_ecore_signal_count_get() > 0) have_signal = 1; - } - /* idlers */ - else - { - for (;;) - { - if (!_ecore_idler_call()) goto start_loop; - if (_ecore_event_exist()) break; - if (_ecore_main_select(0.0) > 0) have_event = 1; - if (_ecore_main_win32_message(0.0) > 0) have_msg = 1; - if (_ecore_signal_count_get() > 0) have_signal = 1; - if (have_event || have_signal || have_msg) break; - next_time = _ecore_timer_next_get(); - if (next_time >= 0) goto start_loop; - if (do_quit) break; - } - } - } - /* timers */ - else - { - /* no idlers */ - if (!_ecore_idler_exist()) - { - if (_ecore_main_select(next_time) > 0) have_event = 1; - if (_ecore_main_win32_message(next_time) > 0) have_msg = 1; - if (_ecore_signal_count_get() > 0) have_signal = 1; - } - /* idlers */ - else - { - for (;;) - { - double cur_time, t; - - if (!_ecore_idler_call()) goto start_loop; - if (_ecore_event_exist()) break; - if (_ecore_main_select(0.0) > 0) have_event = 1; - if (_ecore_main_win32_message(0.0) > 0) have_msg = 1; - if (_ecore_signal_count_get() > 0) have_signal = 1; - if (have_event || have_signal || have_msg) break; - cur_time = ecore_time_get(); - t = ecore_time_get() - cur_time; - if (t >= next_time) break; - next_time = _ecore_timer_next_get(); - if (next_time < 0) goto start_loop; - if (do_quit) break; - } - } - } - } - if (_ecore_fps_debug) - { - t1 = ecore_time_get(); + /* 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(); + 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 */ - process_events: - if (have_event) _ecore_main_fd_handlers_call(); - do - { - /* process signals into events .... */ - while (_ecore_signal_count_get()) _ecore_signal_call(); - /* handle events ... */ - _ecore_event_call(); - _ecore_main_fd_handlers_cleanup(); - } - while (_ecore_main_fd_handlers_buf_call()); - if (have_msg) _ecore_main_win32_message_buf_call(); - while (_ecore_main_win32_message_buf_call()); -/* ok - too much optimising. let's call idle enterers more often. if we - * have events that place more events or jobs etc. on the event queue - * we may never get to call an idle enterer + _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) - */ - _ecore_idle_enterer_call(); + { + /* 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..0acfc6c --- /dev/null +++ b/src/lib/ecore/ecore_pipe.c @@ -0,0 +1,691 @@ +#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; + + _ecore_fd_close_on_exec(fds[0]); + _ecore_fd_close_on_exec(fds[1]); + + 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 index 74eee7f..089212e 100644 --- a/src/lib/ecore/ecore_poll.c +++ b/src/lib/ecore/ecore_poll.c @@ -1,54 +1,71 @@ -#include "ecore_private.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + #include "Ecore.h" +#include "ecore_private.h" -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] = +struct _Ecore_Poller { - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL + EINA_INLIST; + ECORE_MAGIC; + int ibit; + unsigned char delete_me : 1; + Ecore_Task_Cb func; + void *data; }; -static unsigned short poller_counters[16] = +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] = { - 0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0 + 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 int _ecore_poller_cb_timer(void *data); +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 (pollers[i]) + { + min_interval = i; + break; + } } if (min_interval < 0) { - /* no pollers */ - if (timer) - { - ecore_timer_del(timer); - timer = NULL; - } - return; + /* no pollers */ + if (timer) + { + ecore_timer_del(timer); + timer = NULL; + } + return; } interval_incr = (1 << min_interval); interval = interval_incr * poll_interval; @@ -58,101 +75,99 @@ _ecore_poller_next_tick_eval(void) * 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); + 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); - } - } + 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 int -_ecore_poller_cb_timer(void *data) +static Eina_Bool +_ecore_poller_cb_timer(void *data __UNUSED__) { int i; - Ecore_List2 *l; - Ecore_Poller *poller; + Ecore_Poller *poller, *l; int changes = 0; at_tick++; last_tick = ecore_time_get(); - /* we have 16 counters - each incriments every time the poller counter - * "ticks". it incriments by the minimum interval (which can be 1, 2, 4, + /* 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; + 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) - { - for (l = (Ecore_List2 *)pollers[i]; l; l = l->next) - { - poller = (Ecore_Poller *)l; - if (!poller->delete_me) - { - if (!poller->func(poller->data)) - { - if (!poller->delete_me) - { - poller->delete_me = 1; - poller_delete_count++; - } - } - } - } - } + /* 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 = (Ecore_List2 *)pollers[i]; l;) - { - poller = (Ecore_Poller *)l; - l = l->next; - if (poller->delete_me) - { - pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller); - free(poller); - poller_delete_count--; - changes++; - if (poller_delete_count <= 0) break; - } - } - if (poller_delete_count <= 0) break; - } + /* 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 */ @@ -161,116 +176,56 @@ _ecore_poller_cb_timer(void *data) 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 im plies "keep running me" but we have been deleted + * if we do as it implies keep running me" but we have been deleted * anyway */ - if (!timer) return 0; + if (!timer) return ECORE_CALLBACK_CANCEL; /* adjust interval */ ecore_timer_interval_set(timer, poll_cur_interval); - return 1; + return ECORE_CALLBACK_RENEW; } -/** - * @defgroup Ecore_Poll_Group Ecore Poll Functions - * - * These functions are for the need to poll information, but provide a shared - * abstracted API to pool such polling to minimise wakeup and ensure all the - * polling happens in as few spots as possible areound a core poll interval. - * For now only 1 core poller type is supprted: ECORE_POLLER_CORE - */ - - -/** - * Sets the time between ticks (in seconds) for the given ticker clock. - * @param type The ticker type to adjust - * @param poll_time The time (in seconds) between ticks of the clock - * @ingroup Ecore_Poller_Group - * - * This will adjust the time between ticks of the given ticker 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) +ecore_poller_poll_interval_set(Ecore_Poller_Type type __UNUSED__, + double poll_time) { + EINA_MAIN_LOOP_CHECK_RETURN; + + if (poll_time < 0.0) + { + ERR("Poll time %f less than zero, ignored", poll_time); + return; + } + poll_interval = poll_time; _ecore_poller_next_tick_eval(); } -/** - * Gets the time between ticks (in seconds) for the fiven ticker clock. - * @param type The ticker type to query - * @return The time in seconds between ticks of the ticker clock - * @ingroup Ecore_Poller_Group - * - * This will get the time between ticks of the specifider ticker clock. - */ EAPI double -ecore_poller_poll_interval_get(Ecore_Poller_Type type) +ecore_poller_poll_interval_get(Ecore_Poller_Type type __UNUSED__) { + EINA_MAIN_LOOP_CHECK_RETURN_VAL(0.0); return poll_interval; } -/** - * Creates a poller to call the given function at a particular tick interval. - * @param type The ticker type to attach the poller to - * @param interval The poll interval - * @param func The given function. If @p func returns 1, the poller is - * rescheduled for the next tick interval. - * @param data Data to pass to @p func when it is called. - * @return A poller object on success. @c NULL on failure. - * @ingroup Ecore_Poller_Group - * - * This function adds a poller callback that is to be called regularly - * along with all other poller callbacks so the pollers are synchronized with - * all other pollers running off the same poller type and at the same tick - * interval. This should be used for polling things when polling is desired - * or required, and you do not have specific requirements on the exact times - * to poll and want to avoid extra process wakeups for polling. 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 if you are at all - * power conscious. - * - * The @p type parameter defines the poller tick type (there is a virtual - * clock ticking all the time - though ecore avoids making it tick when - * there will not be any work to do at that tick point). There is only one - * ticker at the moment - that is ECORE_POLLER_CORE. This is here for future - * expansion if multiple clocks with different frequencies are really required. - * The default time between ticks for the ECORE_POLLER_CORE ticker is 0.125 - * seconds. - * - * The @p interval is the number of ticker ticks that will pass by in between - * invocations of the @p func callback. This must be between 1 and 32768 - * inclusive, and must be a power of 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768). - * If it is 1, then the function will be called every tick. if it is 2, then it - * will be called every 2nd tick, if it is 8, then every 8th tick etc. Exactly - * which tick is undefined, as only the interval between calls can be defined. - * Ecore will endeavour to keep pollers synchronised and to call as many in - * 1 wakeup event as possible. - * - * This function adds a poller and returns its handle on success and NULL on - * failure. The function @p func will be called at tick intervals described - * above. The function will be passed the @p data pointer as its parameter. - * - * When the poller @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_Poller * -ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), const void *data) +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 = calloc(1, sizeof(Ecore_Poller)); + + 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 */ @@ -278,16 +233,16 @@ ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), ibit = -1; while (interval != 0) { - ibit++; - interval >>= 1; + 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_list2_prepend(pollers[poller->ibit], poller); + 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 @@ -295,59 +250,111 @@ ecore_poller_add(Ecore_Poller_Type type, int interval, int (*func) (void *data), return poller; } -/** - * 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. @c NULL is returned if the function is unsuccessful. - * @ingroup Ecore_Poller_Group - * - * Note: @p 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 delete). - */ +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; + 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; + poller_delete_count++; + poller->delete_me = 1; + return poller->data; } /* not in loop so safe - delete immediately */ data = poller->data; - pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller); - free(poller); + 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_List2 *l; Ecore_Poller *poller; - + for (i = 0; i < 15; i++) { - for (l = (Ecore_List2 *)pollers[i]; l;) - { - poller = (Ecore_Poller *)l; - l = l->next; - pollers[poller->ibit] = _ecore_list2_remove(pollers[poller->ibit], poller); - free(poller); - } + 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 index 50ae9b9..6c4543c 100644 --- a/src/lib/ecore/ecore_private.h +++ b/src/lib/ecore/ecore_private.h @@ -1,477 +1,382 @@ #ifndef _ECORE_PRIVATE_H #define _ECORE_PRIVATE_H -#ifdef HAVE_CONFIG_H -# include +#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_MMAN_H -# include +#ifdef ECORE_DEFAULT_LOG_COLOR +# undef ECORE_DEFAULT_LOG_COLOR #endif +#define ECORE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE -#ifdef EAPI -# undef EAPI +#ifdef ERR +# undef ERR #endif +#define ERR(...) EINA_LOG_DOM_ERR(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) -#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 __GNUC__ -# if __GNUC__ >= 4 -// BROKEN in gcc 4 on amd64 -//# pragma GCC visibility push(hidden) -# endif +#ifdef DBG +# undef DBG #endif +#define DBG(...) EINA_LOG_DOM_DBG(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__) -#if HAVE___ATTRIBUTE__ -# define __UNUSED__ __attribute__((unused)) -#else -# define __UNUSED__ +#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)) +# define MIN(x, y) (((x) > (y)) ? (y) : (x)) #endif #ifndef MAX -# define MAX(x, y) (((x) > (y)) ? (x) : (y)) +# define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif #ifndef ABS -# define ABS(x) ((x) < 0 ? -(x) : (x)) +# define ABS(x) ((x) < 0 ? -(x) : (x)) #endif #ifndef CLAMP # define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) #endif -#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 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)); +#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; +#define FREE(ptr) free(ptr); ptr = NULL; #undef IF_FREE -#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL; +#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; } +#define IF_FN_DEL(_fn, ptr) if (ptr) { _fn(ptr); ptr = NULL; } -inline void ecore_print_warning(const char *function, const char *sparam); +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; \ - } + 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; \ - } +#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); + +Eina_Bool _ecore_fd_close_on_exec(int fd); + +void _ecore_main_shutdown(void); + +#if defined (_WIN32) || defined (__lv2ppu__) || defined (HAVE_EXOTIC) +static inline void _ecore_signal_shutdown(void) { } -typedef unsigned int Ecore_Magic; +static inline void _ecore_signal_init(void) { } -typedef struct _Ecore_List2 Ecore_List2; -typedef struct _Ecore_List2_Data Ecore_List2_Data; +static inline void _ecore_signal_received_process(void) { } -struct _Ecore_List2 -{ - Ecore_List2 *next, *prev; - Ecore_List2 *last; -}; +static inline int _ecore_signal_count_get(void) { return 0; } -struct _Ecore_List2_Data -{ - Ecore_List2 __list_data; - void *data; -}; - -#ifndef _ECORE_H -enum _Ecore_Fd_Handler_Flags -{ - ECORE_FD_READ = 1, - ECORE_FD_WRITE = 2, - ECORE_FD_ERROR = 4 -}; -typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags; -enum _Ecore_Exe_Flags -{ - ECORE_EXE_PIPE_READ = 1, - ECORE_EXE_PIPE_WRITE = 2, - ECORE_EXE_PIPE_ERROR = 4, - ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, - ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, - ECORE_EXE_PIPE_AUTO = 32, - ECORE_EXE_RESPAWN = 64, - ECORE_EXE_USE_SH = 128, - ECORE_EXE_NOT_LEADER = 256 - /* 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 existant 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. - */ -}; -typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; -enum _Ecore_Poller_Type -{ - ECORE_POLLER_CORE = 0 -}; -typedef enum _Ecore_Poller_Type Ecore_Poller_Type; +static inline void _ecore_signal_call(void) { } -#ifndef _WIN32 -typedef struct _Ecore_Exe Ecore_Exe; +#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 -typedef struct _Ecore_Timer Ecore_Timer; -typedef struct _Ecore_Idler Ecore_Idler; -typedef struct _Ecore_Idle_Enterer Ecore_Idle_Enterer; -typedef struct _Ecore_Idle_Exiter Ecore_Idle_Exiter; -typedef struct _Ecore_Fd_Handler Ecore_Fd_Handler; -typedef struct _Ecore_Event_Handler Ecore_Event_Handler; -typedef struct _Ecore_Event_Filter Ecore_Event_Filter; -typedef struct _Ecore_Event Ecore_Event; -typedef struct _Ecore_Animator Ecore_Animator; -typedef struct _Ecore_Poller Ecore_Poller; +void _ecore_exe_init(void); +void _ecore_exe_shutdown(void); #ifndef _WIN32 -struct _Ecore_Exe -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - pid_t pid; - void *data; - char *tag; - char *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 */ - int close_stdin; - - 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 *_ecore_exe_find(pid_t pid); +void *_ecore_exe_event_del_new(void); +void _ecore_exe_event_del_free(void *data, + void *ev); #endif -struct _Ecore_Timer -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - double in; - double at; - double pending; - unsigned char delete_me : 1; - unsigned char just_added : 1; - unsigned char frozen : 1; - int (*func) (void *data); - void *data; -}; - -struct _Ecore_Idler -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int delete_me : 1; - int (*func) (void *data); - void *data; -}; - -struct _Ecore_Idle_Enterer -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int delete_me : 1; - int (*func) (void *data); - void *data; -}; - -struct _Ecore_Idle_Exiter -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int delete_me : 1; - int (*func) (void *data); - void *data; -}; - -struct _Ecore_Fd_Handler -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int fd; - Ecore_Fd_Handler_Flags flags; - int read_active : 1; - int write_active : 1; - int error_active : 1; - int delete_me : 1; - int (*func) (void *data, Ecore_Fd_Handler *fd_handler); - void *data; - int (*buf_func) (void *data, Ecore_Fd_Handler *fd_handler); - void *buf_data; - void (*prep_func) (void *data, Ecore_Fd_Handler *fd_handler); - void *prep_data; -}; - -struct _Ecore_Event_Handler -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int type; - int delete_me : 1; - int (*func) (void *data, int type, void *event); - void *data; -}; - -struct _Ecore_Event_Filter -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int delete_me : 1; - void * (*func_start) (void *data); - int (*func_filter) (void *data, void *loop_data, int type, void *event); - void (*func_end) (void *data, void *loop_data); - void *loop_data; - void *data; -}; - -struct _Ecore_Event -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int type; - void *event; - int delete_me : 1; - void (*func_free) (void *data, void *ev); - void *data; -}; - -struct _Ecore_Animator -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - signed char delete_me : 1; - int (*func) (void *data); - void *data; -}; - -struct _Ecore_Poller -{ - Ecore_List2 __list_data; - ECORE_MAGIC; - int ibit; - signed char delete_me : 1; - int (*func) (void *data); - void *data; -}; +void _ecore_animator_shutdown(void); -#endif +void _ecore_poller_shutdown(void); -EAPI void _ecore_magic_fail(void *d, Ecore_Magic m, Ecore_Magic req_m, const char *fname); +void _ecore_fps_debug_init(void); +void _ecore_fps_debug_shutdown(void); +void _ecore_fps_debug_runtime_add(double t); -void _ecore_timer_shutdown(void); -void _ecore_timer_cleanup(void); -void _ecore_timer_enable_new(void); -double _ecore_timer_next_get(void); -int _ecore_timer_call(double when); +void _ecore_thread_init(void); +void _ecore_thread_shutdown(void); -void _ecore_idler_shutdown(void); -int _ecore_idler_call(void); -int _ecore_idler_exist(void); +void _ecore_glib_init(void); +void _ecore_glib_shutdown(void); -void _ecore_idle_enterer_shutdown(void); -void _ecore_idle_enterer_call(void); -int _ecore_idle_enterer_exist(void); +void _ecore_job_init(void); +void _ecore_job_shutdown(void); -void _ecore_idle_exiter_shutdown(void); -void _ecore_idle_exiter_call(void); -int _ecore_idle_exiter_exist(void); +void _ecore_main_loop_init(void); +void _ecore_main_loop_shutdown(void); -void _ecore_event_shutdown(void); -int _ecore_event_exist(void); -Ecore_Event *_ecore_event_add(int type, void *ev, void (*func_free) (void *data, void *ev), void *data); -void *_ecore_event_del(Ecore_Event *event); -void _ecore_event_call(void); +void _ecore_throttle(void); -EAPI 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_call_flush(void); -void _ecore_main_shutdown(void); +extern int _ecore_main_lock_count; +extern Eina_Lock _ecore_main_loop_lock; -#ifdef _WIN32 -static inline void _ecore_signal_shutdown(void) { } -static inline void _ecore_signal_init(void) { } -static inline int _ecore_signal_count_get(void) { return 0; } -static inline void _ecore_signal_call(void) { } +static inline void +_ecore_lock(void) +{ +#ifdef HAVE_THREAD_SAFETY + eina_lock_take(&_ecore_main_loop_lock); #else -void _ecore_signal_shutdown(void); -void _ecore_signal_init(void); -int _ecore_signal_count_get(void); -void _ecore_signal_call(void); + /* 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); */ +} -#ifdef _WIN32 -static inline void _ecore_exe_init(void) { } -static inline void _ecore_exe_shutdown(void) { } -#else -void _ecore_exe_init(void); -void _ecore_exe_shutdown(void); -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); +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; -void _ecore_animator_shutdown(void); + _ecore_unlock(); + r = func(data); + _ecore_lock(); -void _ecore_poller_shutdown(void); + return r; +} -EAPI void *_ecore_list2_append (void *in_list, void *in_item); -EAPI void *_ecore_list2_prepend (void *in_list, void *in_item); -EAPI void *_ecore_list2_append_relative (void *in_list, void *in_item, void *in_relative); -EAPI void *_ecore_list2_prepend_relative (void *in_list, void *in_item, void *in_relative); -EAPI void *_ecore_list2_remove (void *in_list, void *in_item); -EAPI void *_ecore_list2_find (void *in_list, void *in_item); +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(); -void _ecore_fps_debug_init(void); -void _ecore_fps_debug_shutdown(void); -void _ecore_fps_debug_runtime_add(double t); + 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 -extern int _ecore_fps_debug; +#undef GENERIC_ALLOC_FREE_HEADER #endif diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c index 4c555c6..05fe3b7 100644 --- a/src/lib/ecore/ecore_signal.c +++ b/src/lib/ecore/ecore_signal.c @@ -1,37 +1,56 @@ -#ifndef _WIN32 +#ifdef HAVE_CONFIG_H +# include +#endif + +#include #include #include #include #include #include -#include "ecore_private.h" + #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 */ -#undef SIGRTMIN 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); +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); +static void _ecore_signal_callback_sigpwr(int sig, + siginfo_t *si, + void *foo); #endif -#ifdef SIGRTMIN -static void _ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo); -#endif - -static int _ecore_signal_exe_exit_delay(void *data); +static Eina_Bool _ecore_signal_exe_exit_delay(void *data); //#define MAXSIGQ 256 // 32k #define MAXSIGQ 64 // 8k @@ -47,9 +66,6 @@ static volatile sig_atomic_t sigterm_count = 0; #ifdef SIGPWR static volatile sig_atomic_t sigpwr_count = 0; #endif -#ifdef SIGRTMIN -static volatile sig_atomic_t *sigrt_count = NULL; -#endif static volatile siginfo_t sigchld_info[MAXSIGQ]; static volatile siginfo_t sigusr1_info[MAXSIGQ]; @@ -61,28 +77,21 @@ static volatile siginfo_t sigterm_info[MAXSIGQ]; #ifdef SIGPWR static volatile siginfo_t sigpwr_info[MAXSIGQ]; #endif -#ifdef SIGRTMIN -static volatile siginfo_t *sigrt_info[MAXSIGQ]; -#endif void _ecore_signal_shutdown(void) { -#ifdef SIGRTMIN - int i, num = SIGRTMAX - SIGRTMIN; -#endif - - _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); + _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); + _ecore_signal_callback_set(SIGPWR, (Signal_Handler)SIG_DFL); sigpwr_count = 0; #endif sigchld_count = 0; @@ -93,64 +102,29 @@ _ecore_signal_shutdown(void) sigint_count = 0; sigterm_count = 0; sig_count = 0; - -#ifdef SIGRTMIN - for (i = 0; i < num; i++) - { - _ecore_signal_callback_set(SIGRTMIN + i, (Signal_Handler) SIG_DFL); - sigrt_count[i] = 0; - } - - if (sigrt_count) - { - free((sig_atomic_t *) sigrt_count); - sigrt_count = NULL; - } - - for (i = 0; i < MAXSIGQ; i++) - { - if (sigrt_info[i]) - { - free((siginfo_t *) sigrt_info[i]); - sigrt_info[i] = NULL; - } - } -#endif } void _ecore_signal_init(void) { -#ifdef SIGRTMIN - int i, num = SIGRTMAX - SIGRTMIN; -#endif - _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(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(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); + _ecore_signal_callback_set(SIGPWR, _ecore_signal_callback_sigpwr); #endif +} -#ifdef SIGRTMIN - sigrt_count = calloc(1, sizeof(sig_atomic_t) * num); - assert(sigrt_count); - - for (i = 0; i < MAXSIGQ; i++) - { - sigrt_info[i] = calloc(1, sizeof(siginfo_t) * num); - assert(sigrt_info[i]); - } - - for (i = 0; i < num; i++) - _ecore_signal_callback_set(SIGRTMIN + i, _ecore_signal_callback_sigrt); -#endif +void +_ecore_signal_received_process(void) +{ + while (_ecore_signal_count_get()) _ecore_signal_call(); } int @@ -159,15 +133,20 @@ _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) { -#ifdef SIGRTMIN - int i, num = SIGRTMAX - SIGRTMIN; -#endif volatile sig_atomic_t n; sigset_t oldset, newset; - + int tot; + if (sig_count == 0) return; sigemptyset(&newset); sigaddset(&newset, SIGPIPE); @@ -182,259 +161,260 @@ _ecore_signal_call(void) #ifdef SIGPWR sigaddset(&newset, SIGPWR); #endif -#ifdef SIGRTMIN - for (i = 0; i < num; i++) - sigaddset(&newset, SIGRTMIN + i); -#endif sigprocmask(SIG_BLOCK, &newset, &oldset); if (sigchld_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGCHLD in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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) && (e->exe->flags & (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. - */ - IF_FN_DEL(ecore_timer_del, e->exe->doomsday_clock); - e->exe->doomsday_clock = ecore_timer_add(0.1, _ecore_signal_exe_exit_delay, e); - } - else - { - _ecore_event_add(ECORE_EXE_EVENT_DEL, e, - _ecore_exe_event_del_free, NULL); - } - } - } - sig_count--; + 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) - printf("ECORE WARNING. %i SIGUSR1 in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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; + Ecore_Event_Signal_User *e; - e = _ecore_event_signal_user_new(); - if (e) - { - e->number = 1; + e = _ecore_event_signal_user_new(); + if (e) + { + e->number = 1; - if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo)) - e->data = sigusr1_info[n]; + if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo)) + e->data = sigusr1_info[n]; - ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, NULL, NULL); - } - sig_count--; + _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; } sigusr1_count = 0; - + if (sigusr2_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGUSR2 in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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; + Ecore_Event_Signal_User *e; - e = _ecore_event_signal_user_new(); - if (e) - { - e->number = 2; + e = _ecore_event_signal_user_new(); + if (e) + { + e->number = 2; - if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo)) - e->data = sigusr2_info[n]; + if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo)) + e->data = sigusr2_info[n]; - ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, NULL, NULL); - } - sig_count--; + _ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; } sigusr2_count = 0; - + if (sighup_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGHUP in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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, NULL, NULL); - } - sig_count--; + 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) - printf("ECORE WARNING. %i SIGQUIT in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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; + Ecore_Event_Signal_Exit *e; - e = _ecore_event_signal_exit_new(); - if (e) - { - e->quit = 1; + e = _ecore_event_signal_exit_new(); + if (e) + { + e->quit = 1; - if ((n < MAXSIGQ) && (sigquit_info[n].si_signo)) - e->data = sigquit_info[n]; + if ((n < MAXSIGQ) && (sigquit_info[n].si_signo)) + e->data = sigquit_info[n]; - ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL); - } - sig_count--; + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; } sigquit_count = 0; if (sigint_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGINT in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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; + Ecore_Event_Signal_Exit *e; - e = _ecore_event_signal_exit_new(); - if (e) - { - e->interrupt = 1; + e = _ecore_event_signal_exit_new(); + if (e) + { + e->interrupt = 1; - if ((n < MAXSIGQ) && (sigint_info[n].si_signo)) - e->data = sigint_info[n]; + if ((n < MAXSIGQ) && (sigint_info[n].si_signo)) + e->data = sigint_info[n]; - ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL); - } - sig_count--; + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; } sigint_count = 0; - + if (sigterm_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGTERM in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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; + Ecore_Event_Signal_Exit *e; - e = _ecore_event_signal_exit_new(); - if (e) - { - e->terminate = 1; + e = _ecore_event_signal_exit_new(); + if (e) + { + e->terminate = 1; - if ((n < MAXSIGQ) && (sigterm_info[n].si_signo)) - e->data = sigterm_info[n]; + if ((n < MAXSIGQ) && (sigterm_info[n].si_signo)) + e->data = sigterm_info[n]; - ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL); - } - sig_count--; + _ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, + _ecore_signal_generic_free, NULL); + } + sig_count--; } sigterm_count = 0; - + #ifdef SIGPWR if (sigpwr_count > MAXSIGQ) - printf("ECORE WARNING. %i SIGPWR in queue. max queue size %i. losing " - "siginfo for extra signals.\n", 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, NULL, NULL); - } - sig_count--; + 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 - -#ifdef SIGRTMIN - for (i = 0; i < num; i++) - { - if (sigrt_count[i] > MAXSIGQ) - printf("ECORE WARNING. %i SIGRT%i in queue. max queue size %i. losing " - "siginfo for extra signals.\n", i + 1, sigrt_count[i], MAXSIGQ); - for (n = 0; n < sigrt_count[i]; n++) - { - Ecore_Event_Signal_Realtime *e; - - if ((e = _ecore_event_signal_realtime_new())) - { - e->num = i; - - if ((n < MAXSIGQ) && (sigrt_info[n][i].si_signo)) - e->data = sigrt_info[n][i]; - - ecore_event_add(ECORE_EVENT_SIGNAL_REALTIME, e, NULL, NULL); - } - sig_count--; - } - sigrt_count[i] = 0; - } -#endif + sig_count = 0; + sigprocmask(SIG_SETMASK, &oldset, NULL); } static void -_ecore_signal_callback_set(int sig, Signal_Handler func) +_ecore_signal_callback_set(int sig, + Signal_Handler func) { - struct sigaction sa; + struct sigaction sa; sa.sa_sigaction = func; sa.sa_flags = SA_RESTART | SA_SIGINFO; @@ -443,21 +423,25 @@ _ecore_signal_callback_set(int sig, Signal_Handler func) } static void -_ecore_signal_callback_ignore(int sig __UNUSED__, siginfo_t *si __UNUSED__, void *foo __UNUSED__) +_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__) +_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; + if (si) + sigchld_info[n] = *si; + else + sigchld_info[n].si_signo = 0; } sigchld_count++; @@ -465,96 +449,108 @@ _ecore_signal_callback_sigchld(int sig __UNUSED__, siginfo_t *si, void *foo __UN } static void -_ecore_signal_callback_sigusr1(int sig __UNUSED__, siginfo_t *si, void *foo __UNUSED__) +_ecore_signal_callback_sigusr1(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigusr1_count; if (n < MAXSIGQ) { - if (si) - sigusr1_info[n] = *si; - else - sigusr1_info[n].si_signo = 0; + 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__) +_ecore_signal_callback_sigusr2(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigusr2_count; if (n < MAXSIGQ) { - if (si) - sigusr2_info[n] = *si; - else - sigusr2_info[n].si_signo = 0; + 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__) +_ecore_signal_callback_sighup(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sighup_count; if (n < MAXSIGQ) { - if (si) - sighup_info[n] = *si; - else - sighup_info[n].si_signo = 0; + 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__) +_ecore_signal_callback_sigquit(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigquit_count; if (n < MAXSIGQ) { - if (si) - sigquit_info[n] = *si; - else - sigquit_info[n].si_signo = 0; + 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__) +_ecore_signal_callback_sigint(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigint_count; if (n < MAXSIGQ) { - if (si) - sigint_info[n] = *si; - else - sigint_info[n].si_signo = 0; + 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__) +_ecore_signal_callback_sigterm(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigterm_count; if (n < MAXSIGQ) { - if (si) - sigterm_info[n] = *si; - else - sigterm_info[n].si_signo = 0; + if (si) + sigterm_info[n] = *si; + else + sigterm_info[n].si_signo = 0; } sigterm_count++; sig_count++; @@ -562,41 +558,26 @@ _ecore_signal_callback_sigterm(int sig __UNUSED__, siginfo_t *si, void *foo __UN #ifdef SIGPWR static void -_ecore_signal_callback_sigpwr(int sig __UNUSED__, siginfo_t *si, void *foo __UNUSED__) +_ecore_signal_callback_sigpwr(int sig __UNUSED__, + siginfo_t *si, + void *foo __UNUSED__) { volatile sig_atomic_t n; - n = sigchld_count; + n = sigpwr_count; if (n < MAXSIGQ) { - if (si) - sigpwr_info[n] = *si; - else - sigpwr_info[n].si_signo = 0; + if (si) + sigpwr_info[n] = *si; + else + sigpwr_info[n].si_signo = 0; } sigpwr_count++; sig_count++; } -#endif -#ifdef SIGRTMIN -static void -_ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo __UNUSED__) -{ - volatile sig_atomic_t n; - n = sigchld_count; - if (n < MAXSIGQ) - { - if (si) - sigrt_info[n][sig - SIGRTMIN] = *si; - else - sigrt_info[n][sig - SIGRTMIN].si_signo = 0; - } - sigrt_count[sig - SIGRTMIN]++; - sig_count++; -} #endif -static int +static Eina_Bool _ecore_signal_exe_exit_delay(void *data) { Ecore_Exe_Event_Del *e; @@ -604,10 +585,10 @@ _ecore_signal_exe_exit_delay(void *data) e = data; if (e) { - e->exe->doomsday_clock = NULL; - _ecore_event_add(ECORE_EXE_EVENT_DEL, e, - _ecore_exe_event_del_free, NULL); + _ecore_exe_doomsday_clock_set(e->exe, NULL); + _ecore_event_add(ECORE_EXE_EVENT_DEL, e, + _ecore_exe_event_del_free, NULL); } - return 0; + return ECORE_CALLBACK_CANCEL; } -#endif + diff --git a/src/lib/ecore/ecore_thread.c b/src/lib/ecore/ecore_thread.c new file mode 100644 index 0000000..5c6880b --- /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 index ca7db2c..0eeb1d6 100644 --- a/src/lib/ecore/ecore_time.c +++ b/src/lib/ecore/ecore_time.c @@ -1,30 +1,93 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #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" -/* FIXME: clock_gettime() is an option... */ +#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. - * @return The number of seconds since 12.00AM 1st January 1970. - * @ingroup Ecore_Time_Group + * + * 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; + struct timeval timev; gettimeofday(&timev, NULL); return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000); @@ -32,3 +95,90 @@ ecore_time_get(void) # 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 index 93fce30..343c89f 100644 --- a/src/lib/ecore/ecore_timer.c +++ b/src/lib/ecore/ecore_timer.c @@ -1,53 +1,190 @@ -#include "ecore_private.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + #include "Ecore.h" +#include "ecore_private.h" -static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *data), void *data); +#ifdef WANT_ECORE_TIMER_DUMP +# include +# include +# define ECORE_TIMER_DEBUG_BT_NUM 64 +typedef void (*Ecore_Timer_Bt_Func)(); +#endif -static int timers_added = 0; -static int timers_delete_me = 0; +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 last_check = 0.0; +static double precision = 10.0 / 1000000.0; /** - * @defgroup Ecore_Time_Group Ecore Time Functions + * @addtogroup Ecore_Timer_Group * - * Functions that deal with time. These functions include those that simply - * retrieve it in a given format, and those that create events based on it. + * @{ */ /** + * 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. - * @ingroup Ecore_Time_Group * * This function adds a timer and returns its handle on success and NULL on - * failure. The function @p func will be called every @in@ seconds. The + * 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). + * + * 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, int (*func) (void *data), const void *data) +ecore_timer_add(double in, + Ecore_Task_Cb func, + const void *data) { double now; - Ecore_Timer *timer; + Ecore_Timer *timer = NULL; - if (!func) return NULL; + EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL); + _ecore_lock(); + if (!func) goto unlock; if (in < 0.0) in = 0.0; - timer = calloc(1, sizeof(Ecore_Timer)); - if (!timer) return NULL; + 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; } @@ -56,7 +193,6 @@ ecore_timer_add(double in, int (*func) (void *data), const void *data) * @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. - * @ingroup Ecore_Time_Group * * 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). @@ -64,16 +200,23 @@ ecore_timer_add(double in, int (*func) (void *data), const void *data) 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"); - return NULL; + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_del"); + goto unlock; } - if (timer->delete_me) return timer->data; - timers_delete_me++; - timer->delete_me = 1; - return timer->data; + + data = _ecore_timer_del(timer); + +unlock: + _ecore_unlock(); + return data; } /** @@ -82,203 +225,475 @@ ecore_timer_del(Ecore_Timer *timer) * * @param timer The timer to change. * @param in The interval in seconds. - * @ingroup Ecore_Time_Group */ EAPI void -ecore_timer_interval_set(Ecore_Timer *timer, double in) +ecore_timer_interval_set(Ecore_Timer *timer, + double in) { + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + if (in < 0.0) in = 0.0; if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER)) { - ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, - "ecore_timer_interval_set"); - return; + 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 occurence of a timer. + * 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 dalay to add to the next iteration. - * @ingroup Ecore_Time_Group + * @param add The delay to add to the next iteration. */ EAPI void -ecore_timer_delay(Ecore_Timer *timer, double add) +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_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_delay"); + return; } - if (timer->frozen) + _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)) { - timer->pending += add; + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + __func__); + return; } + _ecore_lock(); + now = ecore_time_get(); + + if (timer->frozen) + add = timer->pending; else - { - timers = _ecore_list2_remove(timers, timer); - _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, timer->data); - } + 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. - * @ingroup Ecore_Time_Group + * @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 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"); - return 0; + ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, + "ecore_timer_pending_get"); + goto unlock; } now = ecore_time_get(); if (timer->frozen) - return timer->pending; - return timer->at - now; + 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_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, "ecore_timer_freeze"); - return ; + goto unlock; } /* Timer already frozen */ if (timer->frozen) - return ; + goto unlock; - timers = _ecore_list2_remove(timers, timer); - suspended = _ecore_list2_prepend(suspended, timer); + 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_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER, "ecore_timer_thaw"); - return ; + goto unlock; } /* Timer not frozen */ if (!timer->frozen) - return ; + goto unlock; - suspended = _ecore_list2_remove(suspended, timer); + 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) { - while (timers) + Ecore_Timer *timer; + + while ((timer = timers)) { - Ecore_Timer *timer; - - timer = timers; - timers = _ecore_list2_remove(timers, timer); - ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); - free(timer); + 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 (suspended) + while ((timer = suspended)) { - Ecore_Timer *timer; - - timer = suspended; - suspended = _ecore_list2_remove(suspended, timer); + suspended = (Ecore_Timer *)eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended)); ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); - free(timer); + ecore_timer_mp_free(timer); } + + timer_current = NULL; } void _ecore_timer_cleanup(void) { - Ecore_List2 *l; + Ecore_Timer *l; + int in_use = 0, todo = timers_delete_me, done = 0; if (!timers_delete_me) return; - for (l = (Ecore_List2 *)timers; l;) + 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; - - timer = (Ecore_Timer *)l; - l = l->next; - if (timer->delete_me) - { - timers = _ecore_list2_remove(timers, timer); - ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); - free(timer); - timers_delete_me--; - if (timers_delete_me == 0) return; - } + 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; + } } - for (l = (Ecore_List2 *)suspended; l;) + + if ((!in_use) && (timers_delete_me)) { - Ecore_Timer *timer; - - timer = (Ecore_Timer *)l; - l = l->next; - if (timer->delete_me) - { - suspended = _ecore_list2_remove(suspended, timer); - ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE); - free(timer); - timers_delete_me--; - if (timers_delete_me == 0) return; - } + 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; } - timers_delete_me = 0; } void _ecore_timer_enable_new(void) { - Ecore_List2 *l; + Ecore_Timer *timer; if (!timers_added) return; timers_added = 0; - for (l = (Ecore_List2 *)timers; l; l = l->next) + 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)) { - Ecore_Timer *timer; - - timer = (Ecore_Timer *)l; - timer->just_added = 0; + if (!((timer->delete_me) || (timer->just_added))) + valid_timer = timer; + timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next; } + + return valid_timer; } double @@ -286,79 +701,117 @@ _ecore_timer_next_get(void) { double now; double in; - Ecore_Timer *timer; - - if (!timers) return -1; - now = ecore_time_get(); - timer = (Ecore_Timer *)timers; - while ((timer) && ((timer->delete_me) || (timer->just_added))) - timer = (Ecore_Timer *)((Ecore_List2 *)timer)->next; - if (!timer) return -1; - in = timer->at - now; + 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; -} +} -int -_ecore_timer_call(double when) +static inline void +_ecore_timer_reschedule(Ecore_Timer *timer, + double when) { - Ecore_List2 *l; - Ecore_Timer *timer; + 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) { - /* User set time backwards */ - for (l = (Ecore_List2 *)timers; l; l = l->next) - { - timer = (Ecore_Timer *)l; - timer->at -= (last_check - when); - } + Ecore_Timer *timer; + /* User set time backwards */ + EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when); } last_check = when; - for (l = (Ecore_List2 *)timers; l; l = l->next) + + if (!timer_current) { - timer = (Ecore_Timer *)l; - if ((timer->at <= when) && - (timer->just_added == 0) && - (timer->delete_me == 0)) - { - timers = _ecore_list2_remove(timers, timer); - _ecore_timer_call(when); - if ((!timer->delete_me) && (timer->func(timer->data))) - { - /* 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->delete_me) - { - 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); - } - else - free(timer); - } - else - free(timer); - return 1; - } + /* 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, int (*func) (void *data), void *data) +_ecore_timer_set(Ecore_Timer *timer, + double at, + double in, + Ecore_Task_Cb func, + void *data) { - Ecore_List2 *l; - + Ecore_Timer *t2; + timers_added = 1; timer->at = at; timer->in = in; @@ -369,17 +822,26 @@ _ecore_timer_set(Ecore_Timer *timer, double at, double in, int (*func) (void *da timer->pending = 0.0; if (timers) { - for (l = ((Ecore_List2 *)(timers))->last; l; l = l->prev) - { - Ecore_Timer *t2; - - t2 = (Ecore_Timer *)l; - if (timer->at > t2->at) - { - timers = _ecore_list2_append_relative(timers, timer, t2); - return; - } - } + 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_list2_prepend(timers, timer); + 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 index 35c2de7..0a832fc 100644 --- a/src/lib/ecore_con/Ecore_Con.h +++ b/src/lib/ecore_con/Ecore_Con.h @@ -1,15 +1,26 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ #ifndef _ECORE_CON_H #define _ECORE_CON_H +#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include + #ifdef EAPI -#undef EAPI +# undef EAPI #endif -#ifdef _MSC_VER -# ifdef BUILDING_DLL -# define EAPI __declspec(dllexport) + +#ifdef _WIN32 +# ifdef EFL_ECORE_CON_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif # else # define EAPI __declspec(dllimport) # endif @@ -25,200 +36,1910 @@ # endif #endif -#include -#include -#ifdef HAVE_NETDB_H -# include -#endif -#include - /** - * @file Ecore_Con.h - * @brief Sockets functions. + * @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 descripters and waiting + * 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 + * 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(). + * 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(). - * - * Whenever a client connection is made to an @c Ecore_Con_Server, a - * @c ECORE_CON_CLIENT_ADD event is emitted. Any event callbacks that are - * called receive a @c Ecore_Con_Client object, which represents a - * connection that that particular client. * * 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 - - typedef struct _Ecore_Con_Server Ecore_Con_Server; /**< A connection handle */ - typedef struct _Ecore_Con_Client Ecore_Con_Client; /**< A connection handle */ - typedef struct _Ecore_Con_Url Ecore_Con_Url; - - typedef enum _Ecore_Con_Type - { - ECORE_CON_LOCAL_USER, - ECORE_CON_LOCAL_SYSTEM, - ECORE_CON_LOCAL_ABSTRACT, - ECORE_CON_REMOTE_SYSTEM, - ECORE_CON_USE_SSL2 = (1 << 4), - ECORE_CON_USE_SSL3 = (1 << 5), - ECORE_CON_USE_TLS = (1 << 6) - } Ecore_Con_Type; #define ECORE_CON_USE_SSL ECORE_CON_USE_SSL2 +#define ECORE_CON_REMOTE_SYSTEM ECORE_CON_REMOTE_TCP - typedef enum _Ecore_Con_Url_Time - { - ECORE_CON_URL_TIME_NONE = 0, - ECORE_CON_URL_TIME_IFMODSINCE, - ECORE_CON_URL_TIME_IFUNMODSINCE, - ECORE_CON_URL_TIME_LASTMOD - } Ecore_Con_Url_Time; - - typedef struct _Ecore_Con_Event_Client_Add Ecore_Con_Event_Client_Add; - typedef struct _Ecore_Con_Event_Client_Del Ecore_Con_Event_Client_Del; - typedef struct _Ecore_Con_Event_Server_Add Ecore_Con_Event_Server_Add; - typedef struct _Ecore_Con_Event_Server_Del Ecore_Con_Event_Server_Del; - typedef struct _Ecore_Con_Event_Client_Data Ecore_Con_Event_Client_Data; - typedef struct _Ecore_Con_Event_Server_Data Ecore_Con_Event_Server_Data; - typedef struct _Ecore_Con_Event_Url_Data Ecore_Con_Event_Url_Data; - typedef struct _Ecore_Con_Event_Url_Complete Ecore_Con_Event_Url_Complete; - typedef struct _Ecore_Con_Event_Url_Progress Ecore_Con_Event_Url_Progress; - - struct _Ecore_Con_Event_Client_Add - { - Ecore_Con_Client *client; - }; - - struct _Ecore_Con_Event_Client_Del - { - Ecore_Con_Client *client; - }; - - struct _Ecore_Con_Event_Server_Add - { - Ecore_Con_Server *server; - }; - - struct _Ecore_Con_Event_Server_Del - { - Ecore_Con_Server *server; - }; - - struct _Ecore_Con_Event_Client_Data - { - Ecore_Con_Client *client; - void *data; - int size; - }; - - struct _Ecore_Con_Event_Server_Data - { - Ecore_Con_Server *server; - void *data; - int size; - }; - - struct _Ecore_Con_Event_Url_Data - { - Ecore_Con_Url *url_con; - int size; - unsigned char data[1]; - }; - - struct _Ecore_Con_Event_Url_Complete - { - Ecore_Con_Url *url_con; - int status; - }; - - struct _Ecore_Con_Event_Url_Progress - { - Ecore_Con_Url *url_con; - struct { - double total; - double now; - } down; - struct { - double total; - double now; - } up; - }; - - EAPI extern int ECORE_CON_EVENT_CLIENT_ADD; - EAPI extern int ECORE_CON_EVENT_CLIENT_DEL; - EAPI extern int ECORE_CON_EVENT_SERVER_ADD; - EAPI extern int ECORE_CON_EVENT_SERVER_DEL; - EAPI extern int ECORE_CON_EVENT_CLIENT_DATA; - EAPI extern int ECORE_CON_EVENT_SERVER_DATA; - EAPI extern int ECORE_CON_EVENT_URL_DATA; - EAPI extern int ECORE_CON_EVENT_URL_COMPLETE; - EAPI extern int ECORE_CON_EVENT_URL_PROGRESS; - - EAPI int ecore_con_init(void); - EAPI int ecore_con_shutdown(void); - - EAPI Ecore_Con_Server *ecore_con_server_add(Ecore_Con_Type type, const char *name, int port, const void *data); - - EAPI Ecore_Con_Server *ecore_con_server_connect(Ecore_Con_Type type, const char *name, int port, const void *data); - EAPI void *ecore_con_server_del(Ecore_Con_Server *svr); - EAPI void *ecore_con_server_data_get(Ecore_Con_Server *svr); - EAPI int ecore_con_server_connected_get(Ecore_Con_Server *svr); - EAPI Ecore_List *ecore_con_server_clients_get(Ecore_Con_Server *svr); - EAPI int ecore_con_server_send(Ecore_Con_Server *svr, const void *data, int size); - EAPI void ecore_con_server_client_limit_set(Ecore_Con_Server *svr, int client_limit, char reject_excess_clients); - EAPI char *ecore_con_server_ip_get(Ecore_Con_Server *svr); - EAPI void ecore_con_server_flush(Ecore_Con_Server *svr); - - EAPI int ecore_con_client_send(Ecore_Con_Client *cl, const void *data, int size); - EAPI Ecore_Con_Server *ecore_con_client_server_get(Ecore_Con_Client *cl); - EAPI void *ecore_con_client_del(Ecore_Con_Client *cl); - EAPI void ecore_con_client_data_set(Ecore_Con_Client *cl, const void *data); - EAPI void *ecore_con_client_data_get(Ecore_Con_Client *cl); - EAPI char *ecore_con_client_ip_get(Ecore_Con_Client *cl); - EAPI void ecore_con_client_flush(Ecore_Con_Client *cl); - - EAPI int ecore_con_ssl_available_get(void); - - EAPI int ecore_con_url_init(void); - EAPI int ecore_con_url_shutdown(void); - EAPI Ecore_Con_Url *ecore_con_url_new(const char *url); - EAPI void ecore_con_url_destroy(Ecore_Con_Url *url_con); - EAPI void ecore_con_url_data_set(Ecore_Con_Url *url_con, void *data); - EAPI void *ecore_con_url_data_get(Ecore_Con_Url *url_con); - EAPI int ecore_con_url_url_set(Ecore_Con_Url *url_con, const char *url); - EAPI void ecore_con_url_fd_set(Ecore_Con_Url *url_con, int fd); - EAPI int ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con); - EAPI int ecore_con_url_send(Ecore_Con_Url *url_con, void *data, size_t length, char *content_type); - EAPI void ecore_con_url_time(Ecore_Con_Url *url_con, Ecore_Con_Url_Time condition, time_t tm); - -#ifdef HAVE_NETDB_H - EAPI int ecore_con_dns_lookup(const char *name, - void (*done_cb)(void *data, struct hostent *hostent), - void *data); -#endif - - EAPI int ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, char *filename, char *user, char *pass, char *upload_dir); - EAPI void ecore_con_url_verbose_set(Ecore_Con_Url *url_con, int verbose); - EAPI void ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, int use_epsv); + +/** + * @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 } diff --git a/src/lib/ecore_con/Ecore_Con_Eet.h b/src/lib/ecore_con/Ecore_Con_Eet.h new file mode 100644 index 0000000..bdf0d2d --- /dev/null +++ b/src/lib/ecore_con/Ecore_Con_Eet.h @@ -0,0 +1,73 @@ +#ifndef _ECORE_CON_EET +# define _ECORE_CON_EET + +#include +#include +#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 + +typedef struct _Ecore_Con_Eet Ecore_Con_Eet; +typedef struct _Ecore_Con_Reply Ecore_Con_Reply; + +typedef void (*Ecore_Con_Eet_Data_Cb)(void *data, Ecore_Con_Reply *reply, const char *protocol_name, void *value); +typedef void (*Ecore_Con_Eet_Raw_Data_Cb)(void *data, Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, size_t length); +typedef Eina_Bool (*Ecore_Con_Eet_Client_Cb)(void *data, Ecore_Con_Reply *reply, Ecore_Con_Client *conn); +typedef Eina_Bool (*Ecore_Con_Eet_Server_Cb)(void *data, Ecore_Con_Reply *reply, Ecore_Con_Server *conn); + +EAPI Ecore_Con_Eet *ecore_con_eet_server_new(Ecore_Con_Server *server); +EAPI Ecore_Con_Eet *ecore_con_eet_client_new(Ecore_Con_Server *server); +EAPI void ecore_con_eet_server_free(Ecore_Con_Eet *ece); + +EAPI void ecore_con_eet_register(Ecore_Con_Eet *ece, const char *name, Eet_Data_Descriptor *edd); + +EAPI void ecore_con_eet_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Data_Cb func, const void *data); +EAPI void ecore_con_eet_data_callback_del(Ecore_Con_Eet *ece, const char *name); + +EAPI void ecore_con_eet_raw_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Raw_Data_Cb func, const void *data); +EAPI void ecore_con_eet_raw_data_callback_del(Ecore_Con_Eet *ece, const char *name); + +EAPI void ecore_con_eet_client_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data); +EAPI void ecore_con_eet_client_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data); + +EAPI void ecore_con_eet_client_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data); +EAPI void ecore_con_eet_client_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data); + +EAPI void ecore_con_eet_server_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data); +EAPI void ecore_con_eet_server_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data); + +EAPI void ecore_con_eet_server_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data); +EAPI void ecore_con_eet_server_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data); + +EAPI void ecore_con_eet_data_set(Ecore_Con_Eet *ece, const void *data); +EAPI void *ecore_con_eet_data_get(Ecore_Con_Eet *ece); + +EAPI Ecore_Con_Eet *ecore_con_eet_reply(Ecore_Con_Reply *reply); +EAPI void ecore_con_eet_send(Ecore_Con_Reply *reply, const char *protocol_name, void *value); +EAPI void ecore_con_eet_raw_send(Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, unsigned int length); + +#endif diff --git a/src/lib/ecore_con/Makefile.am b/src/lib/ecore_con/Makefile.am index aa2e9b8..ce656f7 100644 --- a/src/lib/ecore_con/Makefile.am +++ b/src/lib/ecore_con/Makefile.am @@ -5,33 +5,55 @@ AM_CPPFLAGS = \ -I$(top_builddir)/src/lib/ecore_con \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_srcdir)/src/lib/ecore_con \ -@SSL_CFLAGS@ @CURL_CFLAGS@ - -if BUILD_ECORE_CON +@EFL_ECORE_CON_BUILD@ \ +@SSL_CFLAGS@ \ +@CURL_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@TLS_CFLAGS@ \ +@CARES_CFLAGS@ \ +@EET_CFLAGS@ \ +@WIN32_CPPFLAGS@ lib_LTLIBRARIES = libecore_con.la -include_HEADERS = \ -Ecore_Con.h +includes_HEADERS = Ecore_Con.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_con_la_SOURCES = \ ecore_con.c \ -ecore_con_dns.c \ +ecore_con_socks.c \ +ecore_con_ssl.c \ ecore_con_url.c \ -ecore_con_private.h +ecore_con_alloc.c -libecore_con_la_LIBADD = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -@SSL_LIBS@ @CURL_LIBS@ +libecore_con_la_CFLAGS = @WIN32_CFLAGS@ -libecore_con_la_LDFLAGS = -version-info @version_info@ +if ECORE_HAVE_WIN32 +libecore_con_la_SOURCES += ecore_con_local_win32.c +else +libecore_con_la_SOURCES += ecore_con_local.c +endif -libecore_con_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la +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 +if ECORE_HAVE_EET +libecore_con_la_SOURCES += ecore_con_eet.c +includes_HEADERS += Ecore_Con_Eet.h endif -EXTRA_DIST = \ -ecore_con.c \ -ecore_con_dns.c \ -ecore_con_url.c \ -ecore_con_private.h +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@ @EET_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 index 8bebde0..ab57378 100644 --- a/src/lib/ecore_con/ecore_con.c +++ b/src/lib/ecore_con/ecore_con.c @@ -1,17 +1,41 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include #include -#include -#include -#include #include +#include +#include + +#ifdef HAVE_NETINET_TCP_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif -#include +#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 -#if USE_OPENSSL -#include +#ifdef HAVE_EVIL +# include #endif #include "Ecore.h" @@ -19,27 +43,107 @@ #include "Ecore_Con.h" #include "ecore_con_private.h" -#ifdef HAVE_NETINET_IN_H -# include -#endif -#ifdef HAVE_WINSOCK2_H -# include -#endif +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_cb_dns_lookup(void *data, struct hostent *he); -static void _ecore_con_server_free(Ecore_Con_Server *svr); -static void _ecore_con_client_free(Ecore_Con_Client *cl); -static int _ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _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(void *data, void *ev); -static void _ecore_con_event_client_del_free(void *data, void *ev); -static void _ecore_con_event_client_data_free(void *data, 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_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; @@ -47,936 +151,1142 @@ 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; -static Ecore_List *servers = NULL; -static int init_count = 0; -#if USE_OPENSSL -static int ssl_init_count = 0; #endif -#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)) + if (!ecore_init()) + return --_ecore_con_init_count; -/** - * @defgroup Ecore_Con_Lib_Group Ecore Connection Library Functions - * - * Utility functions that set up and shut down the Ecore Connection - * library. - */ + _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; + } -/** - * Initialises the Ecore_Con library. - * @return Number of times the library has been initialised without being - * shut down. - * @ingroup Ecore_Con_Lib_Group - */ -EAPI int -ecore_con_init(void) -{ - if (++init_count != 1) return init_count; + ecore_con_mempool_init(); - ecore_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(); - /* TODO Remember return value, if it fails, use gethostbyname() */ - ecore_con_dns_init(); - servers = ecore_list_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 init_count; + return _ecore_con_init_count; } -/** - * Shuts down the Ecore_Con library. - * @return Number of times the library has been initialised without being - * shut down. - * @ingroup Ecore_Con_Lib_Group - */ EAPI int ecore_con_shutdown(void) { - if (--init_count != 0) return init_count; + Eina_List *l, *l2; + Ecore_Con_Server *svr; + + if (--_ecore_con_init_count != 0) + return _ecore_con_init_count; - while (!ecore_list_empty_is(servers)) - _ecore_con_server_free(ecore_list_first_remove(servers)); - ecore_list_destroy(servers); - servers = NULL; + 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_dns_shutdown(); + 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; - return init_count; + 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; } /** - * @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions + * @addtogroup Ecore_Con_Server_Group Ecore Connection Server Functions * * Functions that operate on Ecore server objects. + * + * @{ */ /** - * Creates a server to listen for connections. - * - * The socket on which the server listens depends on the connection - * type: - * @li If @a compl_type is @c ECORE_CON_LOCAL_USER, the server will listen on - * the Unix socket "~/.ecore/[name]/[port]". - * @li If @a compl_type is @c ECORE_CON_LOCAL_SYSTEM, the server will listen - * on Unix socket "/tmp/.ecore_service|[name]|[port]". - * @li If @a compl_type is @c ECORE_CON_REMOTE_SYSTEM, the server will listen - * on TCP port @c port. - * - * @param compl_type The connection type. - * @param name Name to associate with the socket. It is used when - * generating the socket name of a Unix socket. Though - * it is not used for the TCP socket, it still needs to - * be a valid character array. @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. - * @ingroup Ecore_Con_Server_Group + * @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_add(Ecore_Con_Type compl_type, + const char *name, + int port, + const void *data) { - Ecore_Con_Server *svr; - Ecore_Con_Type type; - struct sockaddr_in socket_addr; - struct sockaddr_un socket_unix; - struct linger lin; - char buf[4096]; + Ecore_Con_Server *svr; + Ecore_Con_Type type; + + if (port < 0 || !name) + return NULL; /* local user socket: FILE: ~/.ecore/[name]/[port] */ - if (port < 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; - - type = compl_type; -#if USE_OPENSSL - /* unset the SSL flag for the following checks */ - type &= ECORE_CON_TYPE; -#endif - - if ((type == ECORE_CON_LOCAL_USER) || (type == ECORE_CON_LOCAL_SYSTEM) || - (type == ECORE_CON_LOCAL_ABSTRACT)) - { - const char *homedir; - struct stat st; - mode_t pmode, mask; - int socket_unix_len; - - if (!name) goto error; - mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; - - if (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, name); - if (stat(buf, &st) < 0) mkdir(buf, mask); - snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, name, port); - mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; - } - else if (type == ECORE_CON_LOCAL_SYSTEM) - { - mask = 0; - if (name[0] == '/') - { - if (port >= 0) - snprintf(buf, sizeof(buf), "%s|%i", name, port); - else - snprintf(buf, sizeof(buf), "%s", name); - } - else - snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", name, port); - } - else if (type == ECORE_CON_LOCAL_ABSTRACT) - strncpy(buf, name, sizeof(buf)); - pmode = umask(mask); - start: - svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (svr->fd < 0) - { - umask(pmode); - goto error; - } - if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) - { - umask(pmode); - goto error; - } - if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) - { - umask(pmode); - goto error; - } - lin.l_onoff = 1; - lin.l_linger = 0; - if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0) - { - umask(pmode); - goto error; - } - socket_unix.sun_family = AF_UNIX; - if (type == ECORE_CON_LOCAL_ABSTRACT) - { -#ifdef HAVE_ABSTRACT_SOCKET - /* . is a placeholder */ - snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", name); - /* first char null indicates abstract namespace */ - socket_unix.sun_path[0] = '\0'; - socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, name); -#else - fprintf(stderr, "Your system does not support abstract sockets!\n"); - umask(pmode); - goto error; -#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 (connect(svr->fd, (struct sockaddr *)&socket_unix, - socket_unix_len) < 0) - { - if ((type == ECORE_CON_LOCAL_USER) || - (type == ECORE_CON_LOCAL_SYSTEM)) - { - if (unlink(buf) < 0) - { - umask(pmode); - goto error; - } - else - goto start; - } - else - { - umask(pmode); - goto error; - } - } - else - { - umask(pmode); - goto error; - } - } - if (listen(svr->fd, 4096) < 0) - { - umask(pmode); - goto error; - } - svr->path = strdup(buf); - if (!svr->path) - { - umask(pmode); - goto error; - } - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - _ecore_con_svr_handler, svr, NULL, NULL); - umask(pmode); - if (!svr->fd_handler) goto error; - } - else if (type == ECORE_CON_REMOTE_SYSTEM) - { - svr->fd = socket(AF_INET, SOCK_STREAM, 0); - 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, &lin, sizeof(struct linger)) < 0) goto error; - socket_addr.sin_family = AF_INET; - socket_addr.sin_port = htons(port); - socket_addr.sin_addr.s_addr = htonl(INADDR_ANY); - if (bind(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 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_handler, svr, NULL, NULL); - if (!svr->fd_handler) goto error; - } - -#if USE_OPENSSL - if (compl_type & ECORE_CON_SSL) - { - if (!ssl_init_count) - { - SSL_library_init(); - SSL_load_error_strings(); - } - ssl_init_count++; - - switch (compl_type & ECORE_CON_SSL) - { - case ECORE_CON_USE_SSL2: - if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method()))) - goto error; - break; - case ECORE_CON_USE_SSL3: - if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method()))) - goto error; - break; - case ECORE_CON_USE_TLS: - if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) - goto error; - break; - } - - if (!(svr->ssl = SSL_new(svr->ssl_ctx))) - goto error; - - SSL_set_fd(svr->ssl, svr->fd); - } -#endif + if (!svr) + return NULL; svr->name = strdup(name); - if (!svr->name) goto error; - svr->type = type; + if (!svr->name) + goto error; + + svr->type = compl_type; svr->port = port; svr->data = (void *)data; - svr->created = 1; - svr->reject_excess_clients = 0; + 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 = ecore_list_new(); + svr->clients = NULL; svr->ppid = getpid(); - ecore_list_append(servers, svr); + 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 >= 0) close(svr->fd); - if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler); - if (svr->write_buf) free(svr->write_buf); - if (svr->ip) free(svr->ip); -#if USE_OPENSSL - if (svr->ssl) SSL_free(svr->ssl); - if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx); -#endif +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; } -/** - * Creates a server object to represent the server listening at the - * given port. - * - * The socket to which the server connects depends on the connection type: - * @li If @a compl_type is @c ECORE_CON_LOCAL_USER, the function will - * connect to the server listening on the Unix socket - * "~/.ecore/[name]/[port]". - * @li If @a compl_type is @c ECORE_CON_LOCAL_SYSTEM, the function will - * connect to the server listening on the Unix socket - * "/tmp/.ecore_service|[name]|[port]". - * @li If @a compl_type is @c ECORE_CON_REMOTE_SYSTEM, the function will - * connect to the server listening on the TCP port "[name]:[port]". - * - * @param compl_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. - * @ingroup Ecore_Con_Server_Group - */ EAPI Ecore_Con_Server * -ecore_con_server_connect(Ecore_Con_Type compl_type, const char *name, int port, - const void *data) +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; - struct sockaddr_un socket_unix; - int curstate = 0; - char buf[4096]; + Ecore_Con_Server *svr; + Ecore_Con_Type type; - if (!name) return NULL; + 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; - - type = compl_type; -#if USE_OPENSSL - /* unset the SSL flag for the following checks */ - type &= ECORE_CON_TYPE; -#endif - if ((type == ECORE_CON_REMOTE_SYSTEM) && (port < 0)) return NULL; - - if ((type == ECORE_CON_LOCAL_USER) || (type == ECORE_CON_LOCAL_SYSTEM) || - (type == ECORE_CON_LOCAL_ABSTRACT)) - { - const char *homedir; - int socket_unix_len; - - if (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, name, port); - } - else if (type == ECORE_CON_LOCAL_SYSTEM) - { - if (port < 0) - { - if (name[0] == '/') - strncpy(buf, name, sizeof(buf)); - else - snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", name); - } - else - { - if (name[0] == '/') - snprintf(buf, sizeof(buf), "%s|%i", name, port); - else - snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", name, port); - } - } - else if (type == ECORE_CON_LOCAL_ABSTRACT) - strncpy(buf, name, sizeof(buf)); - - svr->fd = socket(AF_UNIX, SOCK_STREAM, 0); - 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, &curstate, sizeof(curstate)) < 0) goto error; - socket_unix.sun_family = AF_UNIX; - - if (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", name); - socket_unix.sun_path[0] = '\0'; - socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, name); -#else - fprintf(stderr, "Your system does not support abstract sockets!\n"); - goto error; -#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) goto error; - svr->path = strdup(buf); - if (!svr->path) goto error; - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ, - _ecore_con_cl_handler, svr, NULL, NULL); - if (!svr->fd_handler) goto error; - - if (!svr->delete_me) - { - /* we got our server! */ - Ecore_Con_Event_Server_Add *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Server_Add)); - if (e) - { - svr->event_count++; - e->server = svr; - ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e, - _ecore_con_event_server_add_free, NULL); - } - } - } + if (!svr) + return NULL; svr->name = strdup(name); - if (!svr->name) goto error; + if (!svr->name) + goto error; + svr->type = compl_type; svr->port = port; svr->data = (void *)data; - svr->created = 0; - svr->reject_excess_clients = 0; + 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; - svr->clients = ecore_list_new(); - ecore_list_append(servers, svr); - ECORE_MAGIC_SET(svr, ECORE_MAGIC_CON_SERVER); - if (type == ECORE_CON_REMOTE_SYSTEM) + type = compl_type & ECORE_CON_TYPE; + + if ((!svr->disable_proxy) && (type > ECORE_CON_LOCAL_ABSTRACT)) { - if (!ecore_con_dns_lookup(svr->name, _ecore_con_cb_dns_lookup, svr)) - goto error; + /* 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); - return svr; + 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); - error: - if (svr->name) free(svr->name); - if (svr->path) free(svr->path); - if (svr->fd >= 0) close(svr->fd); - if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler); -#if USE_OPENSSL - if (svr->ssl) SSL_free(svr->ssl); - if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx); + 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; } -/** - * Closes the connection and frees the given server. - * @param svr The given server. - * @return Data associated with the server when it was created. - * @ingroup Ecore_Con_Server_Group - */ -EAPI void * -ecore_con_server_del(Ecore_Con_Server *svr) +EAPI void +ecore_con_server_timeout_set(Ecore_Con_Server *svr, + double timeout) { - void *data; - if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) { - ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del"); - return NULL; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_set"); + return; } - data = svr->data; - svr->data = NULL; - svr->delete_me = 1; - if (svr->event_count > 0) + + 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)) { - if (svr->fd_handler) - { - ecore_main_fd_handler_del(svr->fd_handler); - svr->fd_handler = NULL; - } + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_timeout_get"); + return 0; } - else + + return svr->created ? svr->client_disconnect_time : svr->disconnect_time; +} + +EAPI void * +ecore_con_server_del(Ecore_Con_Server *svr) +{ + if (!svr) return NULL; + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) { - _ecore_con_server_free(svr); - if (ecore_list_goto(servers, svr)) ecore_list_remove(servers); + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_del"); + return NULL; } - return data; + + if (svr->delete_me) + return NULL; + + _ecore_con_server_kill(svr); + return svr->data; } -/** - * Retrieves the data associated with the given server. - * @param svr The given server. - * @return The associated data. - * @ingroup Ecore_Con_Server_Group - */ 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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_data_get"); + return NULL; } + return svr->data; } -/** - * Retrieves whether the given server is currently connected. - * @todo Check that this function does what the documenter believes it does. - * @param svr The given server. - * @return @c 1 if the server is connected. @c 0 otherwise. - * @ingroup Ecore_Con_Server_Group - */ -EAPI int +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 0; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_connected_get"); + return EINA_FALSE; } - if (svr->connecting) return 0; - return 1; + + if (svr->connecting) + return EINA_FALSE; + + return EINA_TRUE; } -/** - * Retrieves the current list of clients. - * @param svr The given server. - * @return The list of clients on this server. - * @ingroup Ecore_Con_Server_Group - */ -EAPI Ecore_List * +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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, + "ecore_con_server_clients_get"); + return NULL; } + return svr->clients; } -/** - * 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. - * @ingroup Ecore_Con_Server_Group - */ +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) +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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_send"); + return 0; } - if (svr->dead) return 0; - if (!data) return 0; - if (size < 1) 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->write_buf) - { - unsigned char *newbuf; - newbuf = realloc(svr->write_buf, svr->write_buf_size + size); - if (newbuf) svr->write_buf = newbuf; - else return 0; - memcpy(svr->write_buf + svr->write_buf_size, data, size); - svr->write_buf_size += size; - } - else + if (!svr->buf) { - svr->write_buf = malloc(size); - if (!svr->write_buf) return 0; - svr->write_buf_size = size; - memcpy(svr->write_buf, data, size); + 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; } -/** - * 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_Con_Server_Group - */ EAPI void -ecore_con_server_client_limit_set(Ecore_Con_Server *svr, int client_limit, char reject_excess_clients) +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; + 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; } -/** - * 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_Con_Server_Group - */ -EAPI char * +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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_ip_get"); + return NULL; } + return svr->ip; } -/** - * Flushes all pending data to the given server. Will return when done. - * - * @param svr The given server. - * @ingroup Ecore_Con_Server_Group - */ +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_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_server_flush"); + return; } + _ecore_con_server_flush(svr); } /** - * @defgroup Ecore_Con_Client_Group Ecore Connection Client Functions + * @} + */ + +/** + * @addtogroup Ecore_Con_Client_Group Ecore Connection Client Functions * * Functions that operate on Ecore connection client objects. + * + * @{ */ /** - * 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. - * @ingroup Ecore_Con_Client_Group + * @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) +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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_send"); + return 0; } - if (cl->dead) return 0; - if (!data) return 0; - if (size < 1) 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->buf) - { - unsigned char *newbuf; - newbuf = realloc(cl->buf, cl->buf_size + size); - if (newbuf) cl->buf = newbuf; - else return 0; - memcpy(cl->buf + cl->buf_size, data, size); - cl->buf_size += size; - } - else + 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 = malloc(size); - if (!cl->buf) return 0; - cl->buf_size = size; - memcpy(cl->buf, data, size); + 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; } -/** - * Retrieves the server representing the socket the client has - * connected to. - * @param cl The given client. - * @return The server that the client connected to. - * @ingroup Ecore_Con_Client_Group - */ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, + "ecore_con_client_server_get"); + return NULL; } - return cl->server; + + return cl->host_server; } -/** - * Closes the connection and frees memory allocated to the given client. - * @param cl The given client. - * @return Data associated with the client. - * @ingroup Ecore_Con_Client_Group - */ -EAPI void * -ecore_con_client_del(Ecore_Con_Client *cl) +EAPI Eina_Bool +ecore_con_client_connected_get(Ecore_Con_Client *cl) { - void *data; + 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_del"); - return NULL; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, + "ecore_con_client_timeout_set"); + return; } - data = cl->data; - cl->data = NULL; - cl->delete_me = 1; - if (cl->event_count > 0) + + 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)) { - if (cl->fd_handler) - { - ecore_main_fd_handler_del(cl->fd_handler); - cl->fd_handler = NULL; - } + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_timeout_get"); + return 0; } - else + + return cl->disconnect_time; +} + +EAPI void * +ecore_con_client_del(Ecore_Con_Client *cl) +{ + if (!cl) return NULL; + if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_CON_CLIENT)) { - if (ecore_list_goto(cl->server->clients, cl)) - ecore_list_remove(cl->server->clients); - _ecore_con_client_free(cl); + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_del"); + return NULL; } - return data; + + _ecore_con_client_kill(cl); + return cl->data; } -/** - * Sets the data associated with the given client to @p data. - * @param cl The given client. - * @param data What to set the data to. - * @ingroup Ecore_Con_Client_Group - */ EAPI void -ecore_con_client_data_set(Ecore_Con_Client *cl, const void *data) +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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_set"); + return; } + cl->data = (void *)data; } -/** - * Retrieves the data associated with the given client. - * @param cl The given client. - * @return The data associated with @p cl. - * @ingroup Ecore_Con_Client_Group - */ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_CON_CLIENT, "ecore_con_client_data_get"); + return NULL; } + return cl->data; } -/** - * Gets the IP address of a cleint 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. - * This string should not be modified or trusted to stay valid after - * deletion for the @p cl object. If no IP is known NULL is returned. - * @ingroup Ecore_Con_Client_Group - */ -EAPI char * +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; + 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; } -/** - * Flushes all pending data to the given client. Will return when done. - * - * @param cl The given client. - * @ingroup Ecore_Con_Client_Group - */ +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_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; + if (svr->delete_me) 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); +} + /** - * 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_con_ssl_available_get(void) + +void +ecore_con_event_proxy_bind(Ecore_Con_Server *svr) { -#if USE_OPENSSL - return 1; -#else - return 0; -#endif + 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); +// givving errors like this is not a good thing - MAYBET his belongs in debug... but not err. +// 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; - ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE); + 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->write_buf) && (!svr->dead)) - { - _ecore_con_server_flush(svr); - t = ecore_time_get(); - if ((t - t_start) > 0.5) - { - printf("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.\n", - (t - t_start)); - break; - } - } - if (svr->write_buf) free(svr->write_buf); - while (!ecore_list_empty_is(svr->clients)) - _ecore_con_client_free(ecore_list_first_remove(svr->clients)); - ecore_list_destroy(svr->clients); - if ((svr->created) && (svr->path) && (svr->ppid == getpid())) - unlink(svr->path); - if (svr->fd >= 0) close(svr->fd); -#if USE_OPENSSL - if (svr->ssl) + while (svr->buf && (!svr->delete_me)) { - SSL_shutdown(svr->ssl); - SSL_free(svr->ssl); + _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; + } } - if (svr->ssl_ctx) SSL_CTX_free(svr->ssl_ctx); + +#ifdef _WIN32 + ecore_con_local_win32_server_del(svr); #endif - if (svr->name) free(svr->name); - if (svr->path) free(svr->path); - if (svr->ip) free(svr->ip); - if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler); + 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); } @@ -985,702 +1295,1345 @@ _ecore_con_client_free(Ecore_Con_Client *cl) { double t_start, t; - ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE); + if (cl->event_count) return; + t_start = ecore_time_get(); - while ((cl->buf) && (!cl->dead)) - { - _ecore_con_client_flush(cl); - t = ecore_time_get(); - if ((t - t_start) > 0.5) - { - printf("ECORE_CON: 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.\n", - (t - t_start)); - break; - } - } - if (cl->buf) free(cl->buf); - if (cl->fd >= 0) close(cl->fd); - if (cl->fd_handler) ecore_main_fd_handler_del(cl->fd_handler); - if (cl->ip) free(cl->ip); + 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 int -_ecore_con_svr_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +static Eina_Bool +_ecore_con_server_timer(Ecore_Con_Server *svr) { - Ecore_Con_Server *svr; - int new_fd; - struct sockaddr_in incoming; - size_t size_in; + ecore_con_server_del(svr); - svr = data; - if (svr->dead) return 1; - if (svr->delete_me) return 1; - if ((svr->client_limit >= 0) && (!svr->reject_excess_clients)) + svr->until_deletion = NULL; + return ECORE_CALLBACK_CANCEL; +} + +static void +_ecore_con_server_timer_update(Ecore_Con_Server *svr) +{ + if (svr->disconnect_time) { - if (ecore_list_count(svr->clients) >= svr->client_limit) return 1; + 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; + } } - /* a new client */ - size_in = sizeof(struct sockaddr_in); - new_fd = accept(svr->fd, (struct sockaddr *)&incoming, (socklen_t *)&size_in); - if (new_fd >= 0) - { - Ecore_Con_Client *cl; - char buf[64]; - uint32_t ip; - - if ((svr->client_limit >= 0) && (svr->reject_excess_clients)) - { - close(new_fd); - return 1; - } - - cl = calloc(1, sizeof(Ecore_Con_Client)); - if (!cl) - { - close(new_fd); - return 1; - } - fcntl(new_fd, F_SETFL, O_NONBLOCK); - fcntl(new_fd, F_SETFD, FD_CLOEXEC); - cl->fd = new_fd; - cl->server = svr; - cl->fd_handler = - ecore_main_fd_handler_add(cl->fd, ECORE_FD_READ, - _ecore_con_svr_cl_handler, cl, NULL, NULL); - ECORE_MAGIC_SET(cl, ECORE_MAGIC_CON_CLIENT); - ecore_list_append(svr->clients, cl); - if (!svr->path) - { - ip = incoming.sin_addr.s_addr; - snprintf(buf, sizeof(buf), - "%i.%i.%i.%i", - (ip ) & 0xff, - (ip >> 8 ) & 0xff, - (ip >> 16) & 0xff, - (ip >> 24) & 0xff); - cl->ip = strdup(buf); - } - if (!cl->delete_me) - { - Ecore_Con_Event_Client_Add *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Client_Add)); - if (e) - { - cl->event_count++; - e->client = cl; - ecore_event_add(ECORE_CON_EVENT_CLIENT_ADD, e, - _ecore_con_event_client_add_free, NULL); - } - } - } - return 1; -} - -#if USE_OPENSSL -/* Tries to connect an Ecore_Con_Server to an SSL host. - * Returns 1 on success, -1 on fatal errors and 0 if the caller - * should try again later. - */ -static int -svr_try_connect_ssl(Ecore_Con_Server *svr) + 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) { - int res, ssl_err, flag = 0; + Ecore_Con_Server *svr; + struct linger lin; + const char *memerr = NULL; + + svr = data; - if (!ssl_init_count) + errno = 0; + if (!net_info) /* error message has already been handled */ { - SSL_library_init(); - SSL_load_error_strings(); + svr->delete_me = EINA_TRUE; + goto error; } - ssl_init_count++; - res = SSL_connect(svr->ssl); - if (res == 1) return 1; - ssl_err = SSL_get_error(svr->ssl, res); + 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 (ssl_err == SSL_ERROR_NONE) return 1; - if (ssl_err == SSL_ERROR_WANT_READ) flag = ECORE_FD_READ; - else if (ssl_err == SSL_ERROR_WANT_WRITE) flag = ECORE_FD_WRITE; - else return -1; - if (svr->fd_handler) + 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) { - if (flag) ecore_main_fd_handler_active_set(svr->fd_handler, flag); +#ifdef HAVE_NETINET_TCP_H + int flag = 1; + + if (setsockopt(svr->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, + sizeof(int)) < 0) +#endif + { + goto error; + } } - return 0; + + 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); } -#endif static void -kill_server(Ecore_Con_Server *svr) +_ecore_con_cb_udp_listen(void *data, + Ecore_Con_Info *net_info) { - if (!svr->delete_me) + 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 */ { - Ecore_Con_Event_Server_Del *e; + 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; - e = calloc(1, sizeof(Ecore_Con_Event_Server_Del)); - if (e) - { - svr->event_count++; - e->server = svr; - ecore_event_add(ECORE_CON_EVENT_SERVER_DEL, e, - _ecore_con_event_server_del_free, NULL); - } + 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 } - svr->dead = 1; - if (svr->fd_handler) ecore_main_fd_handler_del(svr->fd_handler); - svr->fd_handler = NULL; + 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_dns_lookup(void *data, struct hostent *he) +_ecore_con_cb_tcp_connect(void *data, + Ecore_Con_Info *net_info) { - Ecore_Con_Server *svr; - struct sockaddr_in socket_addr; - int curstate = 0; - char buf[64]; - uint32_t ip; + Ecore_Con_Server *svr; + int res; + int curstate = 0; + const char *memerr = NULL; svr = data; - if (!he) goto error; - svr->fd = socket(AF_INET, SOCK_STREAM, 0); + 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, &curstate, sizeof(curstate)) < 0) + + if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate)) < 0) goto error; - socket_addr.sin_family = AF_INET; - socket_addr.sin_port = htons(svr->port); - memcpy((struct in_addr *)&socket_addr.sin_addr, - he->h_addr, sizeof(struct in_addr)); - if (connect(svr->fd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_in)) < 0) - { - if (errno != EINPROGRESS) - goto error; - svr->connecting = 1; - svr->fd_handler = - ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ | ECORE_FD_WRITE, - _ecore_con_cl_handler, svr, NULL, NULL); + + 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->fd_handler) goto error; - ip = socket_addr.sin_addr.s_addr; - snprintf(buf, sizeof(buf), - "%i.%i.%i.%i", - (ip ) & 0xff, - (ip >> 8 ) & 0xff, - (ip >> 16) & 0xff, - (ip >> 24) & 0xff); - svr->ip = strdup(buf); - -#if USE_OPENSSL + 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) { - if (!ssl_init_count) - { - SSL_library_init(); - SSL_load_error_strings(); - } - ssl_init_count++; - - switch (svr->type & ECORE_CON_SSL) - { - case ECORE_CON_USE_SSL2: - if (!(svr->ssl_ctx = SSL_CTX_new(SSLv2_client_method()))) - goto error; - break; - case ECORE_CON_USE_SSL3: - if (!(svr->ssl_ctx = SSL_CTX_new(SSLv3_client_method()))) - goto error; - break; - case ECORE_CON_USE_TLS: - if (!(svr->ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) - goto error; - break; - } - - if (!(svr->ssl = SSL_new(svr->ssl_ctx))) - goto error; - - SSL_set_fd(svr->ssl, svr->fd); + 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; } -#endif + + 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: - kill_server(svr); +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 int +static Ecore_Con_State svr_try_connect_plain(Ecore_Con_Server *svr) { + int res; int so_err = 0; - unsigned int size = sizeof(int); + 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; - if (getsockopt(svr->fd, SOL_SOCKET, SO_ERROR, &so_err, &size) < 0) - so_err = -1; +#else + if (res < 0) + so_err = errno; + + if ((so_err == EINPROGRESS) && !svr->delete_me) + return ECORE_CON_INPROGRESS; + +#endif - if (so_err != 0) + if (so_err) { - /* we lost our server! */ - kill_server(svr); + /* 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)) { - if (!svr->delete_me) - { - /* we got our server! */ - Ecore_Con_Event_Server_Add *e; + 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; + } - svr->connecting = 0; - e = calloc(1, sizeof(Ecore_Con_Event_Server_Add)); - if (e) - { - svr->event_count++; - e->server = svr; - ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e, - _ecore_con_event_server_add_free, NULL); - } - } - if (svr->fd_handler) - { - if (!svr->write_buf) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - } + cl->client_addr = malloc(client_addr_len); + if (!cl->client_addr) + { + clerr = "Memory allocation failure when attempting to add a new client"; + goto error; } - return (!svr->dead); + 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); + { + Ecore_Event *ev; + + EINA_LIST_FREE(cl->event_count, ev) + { + svr->event_count = eina_list_remove(svr->event_count, ev); + ecore_event_del(ev); + } + } + free(cl); + if (clerr || errno) ecore_con_event_server_error(svr, clerr ?: strerror(errno)); + return ECORE_CALLBACK_RENEW; } -/* returns 1 on success, 0 on failure */ -static int svr_try_connect(Ecore_Con_Server *svr) +static void +_ecore_con_cl_read(Ecore_Con_Server *svr) { -#if USE_OPENSSL - if (!svr->ssl) + 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)) { -#endif - return svr_try_connect_plain(svr); -#if USE_OPENSSL + 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 - switch (svr_try_connect_ssl(svr)) { - case 1: - return svr_try_connect_plain(svr); - case -1: - kill_server(svr); - return 0; - default: - return 0; + { + 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 || ((!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 int -_ecore_con_cl_handler(void *data, Ecore_Fd_Handler *fd_handler) +static Eina_Bool +_ecore_con_svr_udp_handler(void *data, + Ecore_Fd_Handler *fd_handler) { - Ecore_Con_Server *svr; -#if USE_OPENSSL - int ssl_err = SSL_ERROR_NONE; -#endif + 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->dead) return 1; - if (svr->delete_me) return 1; - if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + + if (svr->delete_me) + return ECORE_CALLBACK_RENEW; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) { - unsigned char *inbuf = NULL; - int inbuf_num = 0; + _ecore_con_client_flush(cl); + return ECORE_CALLBACK_RENEW; + } - if (svr->connecting && !svr_try_connect(svr)) - return 1; + if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) + return ECORE_CALLBACK_RENEW; - for (;;) - { - int num, lost_server; - char buf[READBUFSIZ]; +#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); - lost_server = 0; -#if USE_OPENSSL - if (!svr->ssl) - { -#endif - if ((num = read(svr->fd, buf, READBUFSIZ)) < 1) - { - lost_server = ((errno == EIO) || - (errno == EBADF) || - (errno == EPIPE) || - (errno == EINVAL) || - (errno == ENOSPC) || - (num == 0)); - /* is num == 0 is right - when the server closes us - * off we will get this (as this is called when select - * tells us there is data to read!) - */ - } -#if USE_OPENSSL - } - else - { - num = SSL_read(svr->ssl, buf, READBUFSIZ); - if (num < 1) - { - ssl_err = SSL_get_error(svr->ssl, num); - lost_server = (ssl_err == SSL_ERROR_ZERO_RETURN); - if (ssl_err == SSL_ERROR_SYSCALL) - { - if (num == 0) lost_server = 1; - else - { - lost_server = ((errno == EIO) || - (errno == EBADF) || - (errno == EPIPE) || - (errno == EINVAL) || - (errno == ENOSPC) || - (errno == ECONNRESET)); - } - } - } - else - ssl_err = SSL_ERROR_NONE; - } -#endif - if (num < 1) - { - if (inbuf) - { - if (!svr->delete_me) - { - Ecore_Con_Event_Server_Data *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Server_Data)); - if (e) - { - svr->event_count++; - e->server = svr; - e->data = inbuf; - e->size = inbuf_num; - ecore_event_add(ECORE_CON_EVENT_SERVER_DATA, e, - _ecore_con_event_server_data_free, - NULL); - } - } - } - if (lost_server) - { - /* we lost our server! */ - kill_server(svr); - return 1; - } - break; - } - else - { - inbuf = realloc(inbuf, inbuf_num + num); - memcpy(inbuf + inbuf_num, buf, num); - inbuf_num += num; - } - } - -#if USE_OPENSSL - if (svr->fd_handler) - { - if (svr->ssl && ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); - else if (svr->ssl && ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_WRITE); - } +#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; } - else if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) + + +/* 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 { - if (svr->connecting && !svr_try_connect (svr)) - return 1; - _ecore_con_server_flush(svr); + 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; } - return 1; + 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 int -_ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler) +static Eina_Bool +_ecore_con_svr_cl_handler(void *data, + Ecore_Fd_Handler *fd_handler) { - Ecore_Con_Client *cl; + Ecore_Con_Client *cl; cl = data; - if (cl->dead) return 1; - if (cl->delete_me) return 1; - if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) - { - unsigned char *inbuf = NULL; - int inbuf_num = 0; - - for (;;) - { - char buf[65536]; - int num; - - errno = 0; - num = read(cl->fd, buf, 65536); - if (num < 1) - { - if (inbuf) - { - if (!cl->delete_me) - { - Ecore_Con_Event_Client_Data *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Client_Data)); - if (e) - { - cl->event_count++; - e->client = cl; - e->data = inbuf; - e->size = inbuf_num; - ecore_event_add(ECORE_CON_EVENT_CLIENT_DATA, e, - _ecore_con_event_client_data_free, - NULL); - } - } - } - if ((errno == EIO) || (errno == EBADF) || - (errno == EPIPE) || (errno == EINVAL) || - (errno == ENOSPC) || (num == 0)/* is num == 0 right? */) - { - if (!cl->delete_me) - { - /* we lost our client! */ - Ecore_Con_Event_Client_Del *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Client_Del)); - if (e) - { - cl->event_count++; - e->client = cl; - ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e, - _ecore_con_event_client_del_free, - NULL); - } - } - cl->dead = 1; - if (cl->fd_handler) - ecore_main_fd_handler_del(cl->fd_handler); - cl->fd_handler = NULL; - } - break; - } - else - { - inbuf = realloc(inbuf, inbuf_num + num); - memcpy(inbuf + inbuf_num, buf, num); - inbuf_num += num; - } - } + 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 1; + + return ECORE_CALLBACK_RENEW; } static void _ecore_con_server_flush(Ecore_Con_Server *svr) { - int count, num, lost_server = 0; -#if USE_OPENSSL - int ssl_err = SSL_ERROR_NONE; + int count, num; + size_t buf_len, buf_offset; + const unsigned char *buf; + + DBG("(svr=%p,buf=%p)", svr, svr->buf); +#ifdef _WIN32 + if (ecore_con_local_win32_server_flush(svr)) + return; #endif - if (!svr->write_buf) return; + 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 - */ - if (svr->write_buf_size == svr->write_buf_offset) - return; - - num = svr->write_buf_size - svr->write_buf_offset; -#if USE_OPENSSL - if (!svr->ssl) + * 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) { -#endif - count = write(svr->fd, svr->write_buf + svr->write_buf_offset, num); - if (count < 1) - lost_server = (errno == EIO || errno == EBADF || - errno == EPIPE || errno == EINVAL || errno == ENOSPC); -#if USE_OPENSSL + 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) { - count = SSL_write(svr->ssl, svr->write_buf + svr->write_buf_offset, num); + if ((errno != EAGAIN) && (errno != EINTR)) + { + ecore_con_event_server_error(svr, strerror(errno)); + _ecore_con_server_kill(svr); + } + return; + } - if (count < 1) - { - ssl_err = SSL_get_error(svr->ssl, count); - lost_server = (ssl_err == SSL_ERROR_ZERO_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 (lost_server) + if (!cl->buf && cl->fd_handler) { - /* we lost our server! */ - kill_server(svr); - return; + ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + return; } - if (count < 1) + if (cl->handshaking) { -#if USE_OPENSSL - if (svr->fd_handler) - { - if (svr->ssl && ssl_err == SSL_ERROR_WANT_READ) - ecore_main_fd_handler_active_set(svr->fd_handler, - ECORE_FD_READ); - else if (svr->ssl && ssl_err == SSL_ERROR_WANT_WRITE) - ecore_main_fd_handler_active_set(svr->fd_handler, - ECORE_FD_WRITE); - } -#endif - return; + if (ecore_con_ssl_client_init(cl)) + count = -1; + + _ecore_con_cl_timer_update(cl); } - svr->write_buf_offset += count; - if (svr->write_buf_offset >= svr->write_buf_size) + if (!count) { - svr->write_buf_size = 0; - svr->write_buf_offset = 0; - free(svr->write_buf); - svr->write_buf = NULL; - if (svr->fd_handler) - ecore_main_fd_handler_active_set(svr->fd_handler, ECORE_FD_READ); + 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); } -} -static void -_ecore_con_client_flush(Ecore_Con_Client *cl) -{ - int count, 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 (!cl->buf) return; - num = cl->buf_size - cl->buf_offset; - count = write(cl->fd, cl->buf + cl->buf_offset, num); - if (count < 1) - { - if ((errno == EIO) || (errno == EBADF) || (errno == EPIPE) || - (errno == EINVAL) || (errno == ENOSPC)) - { - if (!cl->delete_me) - { - /* we lost our client! */ - Ecore_Con_Event_Client_Del *e; - - e = calloc(1, sizeof(Ecore_Con_Event_Client_Del)); - if (e) - { - cl->event_count++; - e->client = cl; - ecore_event_add(ECORE_CON_EVENT_CLIENT_DEL, e, - _ecore_con_event_client_del_free, NULL); - } - cl->dead = 1; - if (cl->fd_handler) - ecore_main_fd_handler_del(cl->fd_handler); - cl->fd_handler = NULL; - } - } - return; - } - cl->buf_offset += count; - if (cl->buf_offset >= cl->buf_size) - { - cl->buf_size = 0; - cl->buf_offset = 0; - free(cl->buf); - cl->buf = NULL; - if (cl->fd_handler) - ecore_main_fd_handler_active_set(cl->fd_handler, ECORE_FD_READ); + 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(void *data __UNUSED__, void *ev) +_ecore_con_event_client_add_free(Ecore_Con_Server *svr, + void *ev) { Ecore_Con_Event_Client_Add *e; e = ev; - e->client->event_count--; - if ((e->client->event_count == 0) && (e->client->delete_me)) - ecore_con_client_del(e->client); - free(e); + if (e->client) + { + Eina_Bool svrfreed = EINA_FALSE; + + 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); + svrfreed = EINA_TRUE; + } + } + if (!svrfreed) + { + 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(void *data __UNUSED__, void *ev) +_ecore_con_event_client_del_free(Ecore_Con_Server *svr, + void *ev) { Ecore_Con_Event_Client_Del *e; e = ev; - e->client->event_count--; - if ((e->client->event_count == 0) && (e->client->delete_me)) - ecore_con_client_del(e->client); - free(e); + if (e->client) + { + Eina_Bool svrfreed = EINA_FALSE; + + 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); + svrfreed = EINA_TRUE; + } + } + if (!svrfreed) + { + 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_data_free(void *data __UNUSED__, void *ev) +_ecore_con_event_client_write_free(Ecore_Con_Server *svr, + Ecore_Con_Event_Client_Write *e) +{ + if (e->client) + { + Eina_Bool svrfreed = EINA_FALSE; + + 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); + svrfreed = EINA_TRUE; + } + } + if (!svrfreed) + { + 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; - e->client->event_count--; - if (e->data) free(e->data); - if ((e->client->event_count == 0) && (e->client->delete_me)) - ecore_con_client_del(e->client); - free(e); + if (e->client) + { + Eina_Bool svrfreed = EINA_FALSE; + + 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); + svrfreed = EINA_TRUE; + } + if (!svrfreed) + { + 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_free(void *data __UNUSED__, + void *ev) { Ecore_Con_Event_Server_Add *e; e = ev; - e->server->event_count--; - if ((e->server->event_count == 0) && (e->server->delete_me)) - ecore_con_server_del(e->server); - free(e); + 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_free(void *data __UNUSED__, + void *ev) { Ecore_Con_Event_Server_Del *e; e = ev; - e->server->event_count--; - if ((e->server->event_count == 0) && (e->server->delete_me)) - ecore_con_server_del(e->server); - free(e); + 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_free(void *data __UNUSED__, + void *ev) { Ecore_Con_Event_Server_Data *e; e = ev; - e->server->event_count--; - if (e->data) free(e->data); - if ((e->server->event_count == 0) && (e->server->delete_me)) - ecore_con_server_del(e->server); - free(e); + 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) + { + Eina_Bool svrfreed = EINA_FALSE; + + if (eina_list_data_find(svr->clients, e->client)) + { + e->client->event_count = eina_list_remove(e->client->event_count, e); + if ((!e->client->event_count) && (e->client->delete_me)) + { + _ecore_con_client_free(e->client); + svrfreed = EINA_TRUE; + } + } + svr->event_count = eina_list_remove(svr->event_count, e); + if (!svrfreed) + { + 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 index e9c64de..3671576 100644 --- a/src/lib/ecore_con/ecore_con_dns.c +++ b/src/lib/ecore_con/ecore_con_dns.c @@ -1,210 +1,344 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* - * Simple dns lookup - * - * http://www.faqs.org/rfcs/rfc1035.html - * man resolv.conf - * - * And a sneakpeek at ares, ftp://athena-dist.mit.edu/pub/ATHENA/ares/ - */ -/* - * TODO - * * Check env LOCALDOMAIN to override search - * * Check env RES_OPTIONS to override options + * This version of ecore_con_info uses dns.c to provide asynchronous dns lookup. * - * * Read /etc/host.conf - * * host.conf env - * RESOLV_HOST_CONF, RESOLV_SERV_ORDER - * * Check /etc/hosts - * - * * Caching - * We should store all names returned when CNAME, might have different ttl. - * Check against search and hostname when querying cache? - * * Remember all querys and delete them on shutdown - * - * * Need more buffer overflow checks. + * dns.c is written by William Ahern: + * http://25thandclement.com/~william/projects/dns.c.html */ -#include "ecore_private.h" + +#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" -#include -#include -#include -#include -#include -#include +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 _CB_Data CB_Data; +typedef struct _Ecore_Con_DNS Ecore_Con_DNS; -struct _CB_Data +struct _Ecore_Con_DNS { - Ecore_List2 __list_data; - void (*cb_done) (void *data, struct hostent *hostent); - void *data; + 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; - pid_t pid; - Ecore_Event_Handler *handler; - int fd2; + Ecore_Timer *timer; }; -static void _ecore_con_dns_readdata(CB_Data *cbdata); -static void _ecore_con_dns_slave_free(CB_Data *cbdata); -static int _ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event); +static int _ecore_con_dns_init = 0; +static dns_resolv_conf *resconf = NULL; +static dns_hosts *hosts = NULL; -static int dns_init = 0; -static Ecore_List2 *dns_slaves = NULL; - -int -ecore_con_dns_init(void) +static void +_ecore_con_dns_free(Ecore_Con_DNS *dns) { - dns_init++; - return dns_init; + 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); } -int -ecore_con_dns_shutdown(void) +static Eina_Bool +_dns_addrinfo_get(Ecore_Con_DNS *dns, const char *addr, int port) { - dns_init--; - if (dns_init == 0) - { - while (dns_slaves) _ecore_con_dns_slave_free((CB_Data *)dns_slaves); - } - return dns_init; + 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; } -int -ecore_con_dns_lookup(const char *name, - void (*done_cb) (void *data, struct hostent *hostent), - void *data) +static int +_ecore_con_dns_check(Ecore_Con_DNS *dns) { - CB_Data *cbdata; - int fd[2]; - - if (pipe(fd) < 0) 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_dns_data_handler, - cbdata, - NULL, NULL))) - { - free(cbdata); - close(fd[0]); - close(fd[1]); - return 0; - } - - if ((cbdata->pid = fork()) == 0) - { - struct hostent *he; - - /* CHILD */ - he = gethostbyname(name); - if (he) - { - struct in_addr addr; - - memcpy((struct in_addr *)&addr, he->h_addr, - sizeof(struct in_addr)); - write(fd[1], &(addr.s_addr), sizeof(in_addr_t)); - } - close(fd[1]); -# ifdef __USE_ISOC99 - _Exit(0); -# else - _exit(0); -# endif - } - /* PARENT */ - cbdata->handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _ecore_con_dns_exit_handler, cbdata); - if (!cbdata->handler) + struct addrinfo *ent = NULL; + int error = 0; + + error = dns_ai_nextent(&ent, dns->ai); + + switch (error) { - ecore_main_fd_handler_del(cbdata->fdh); - free(cbdata); - close(fd[0]); - close(fd[1]); - return 0; + case 0: + break; + case EAGAIN: + return 1; + default: + ERR("resolve failed: %s", dns_strerror(error)); + goto error; } - dns_slaves = _ecore_list2_append(dns_slaves, cbdata); - return 1; + + { + 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 void -_ecore_con_dns_readdata(CB_Data *cbdata) +static Eina_Bool +_dns_fd_cb(Ecore_Con_DNS *dns, Ecore_Fd_Handler *fdh __UNUSED__) { - struct hostent he; - struct in_addr addr; - char *addr2; - ssize_t size; - - size = read(ecore_main_fd_handler_fd_get(cbdata->fdh), &(addr.s_addr), - sizeof(in_addr_t)); - if (size == sizeof(in_addr_t)) + 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)) { - addr2 = (char *)&addr; - he.h_addrtype = AF_INET; - he.h_length = sizeof(in_addr_t); - he.h_addr_list = &addr2; - cbdata->cb_done(cbdata->data, &he); + 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 - cbdata->cb_done(cbdata->data, NULL); - cbdata->cb_done = NULL; + ecore_main_fd_handler_active_set(dns->fdh, dns_ai_events(dns->ai)); + return ECORE_CALLBACK_RENEW; } -static void -_ecore_con_dns_slave_free(CB_Data *cbdata) +static Eina_Bool +_dns_timer_cb(Ecore_Con_DNS *dns) { - dns_slaves = _ecore_list2_remove(dns_slaves, cbdata); - close(ecore_main_fd_handler_fd_get(cbdata->fdh)); - close(cbdata->fd2); - ecore_main_fd_handler_del(cbdata->fdh); - ecore_event_handler_del(cbdata->handler); - free(cbdata); + dns->done_cb(dns->data, NULL); + _ecore_con_dns_free(dns); + dns->timer = NULL; + return EINA_FALSE; } -static int -_ecore_con_dns_data_handler(void *data, Ecore_Fd_Handler *fd_handler) +int +ecore_con_info_init(void) { - CB_Data *cbdata; + int err; + if (_ecore_con_dns_init) return ++_ecore_con_dns_init; - cbdata = data; - if (cbdata->cb_done) + resconf = dns_resconf_local(&err); + if (!resconf) { - if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) - _ecore_con_dns_readdata(cbdata); - else - { - cbdata->cb_done(cbdata->data, NULL); - cbdata->cb_done = NULL; - } + ERR("resconf_open: %s", dns_strerror(err)); + return 0; } - _ecore_con_dns_slave_free(cbdata); - 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; } -static int -_ecore_con_dns_exit_handler(void *data, int type __UNUSED__, void *event) +int +ecore_con_info_shutdown(void) { - CB_Data *cbdata; - Ecore_Exe_Event_Del *ev; - - ev = event; - cbdata = data; - if (cbdata->pid != ev->pid) return 1; + 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; - _ecore_con_dns_slave_free(cbdata); +} + +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_eet.c b/src/lib/ecore_con/ecore_con_eet.c new file mode 100644 index 0000000..ece348e --- /dev/null +++ b/src/lib/ecore_con/ecore_con_eet.c @@ -0,0 +1,796 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "Ecore_Con_Eet.h" + +#define ECORE_CON_EET_RAW_MAGIC 0xDEAD007 + +typedef struct _Ecore_Con_Eet_Data Ecore_Con_Eet_Data; +typedef struct _Ecore_Con_Eet_Raw_Data Ecore_Con_Eet_Raw_Data; +typedef struct _Ecore_Con_Eet_Client Ecore_Con_Eet_Client; +typedef struct _Ecore_Con_Eet_Server Ecore_Con_Eet_Server; + +struct _Ecore_Con_Reply +{ + Ecore_Con_Eet *ece; + Ecore_Con_Client *client; + + Eet_Connection *econn; + + char *buffer_section; + unsigned char *buffer; + unsigned int buffer_length; + unsigned int buffer_current; + Ecore_Con_Eet_Raw_Data *buffer_handler; +}; + +struct _Ecore_Con_Eet_Data +{ + Ecore_Con_Eet_Data_Cb func; + const char *name; + const void *data; +}; + +struct _Ecore_Con_Eet_Raw_Data +{ + Ecore_Con_Eet_Raw_Data_Cb func; + const char *name; + const void *data; +}; + +struct _Ecore_Con_Eet_Client +{ + Ecore_Con_Eet_Client_Cb func; + const void *data; +}; + +struct _Ecore_Con_Eet_Server +{ + Ecore_Con_Eet_Server_Cb func; + const void *data; +}; + +struct _Ecore_Con_Eet +{ + Ecore_Con_Server *server; + + Ecore_Event_Handler *handler_add; + Ecore_Event_Handler *handler_del; + Ecore_Event_Handler *handler_data; + + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor *matching; + + Eina_Hash *data_callbacks; + Eina_Hash *raw_data_callbacks; + + union { + struct { + Eina_List *connections; + Eina_List *client_connect_callbacks; + Eina_List *client_disconnect_callbacks; + } server; + struct { + Ecore_Con_Reply *r; + Eina_List *server_connect_callbacks; + Eina_List *server_disconnect_callbacks; + } client; + } u; + + const void *data; + + Eina_Bool client : 1; +}; + +static void +_ecore_con_eet_data_free(void *data) +{ + Ecore_Con_Eet_Data *eced = data; + + eina_stringshare_del(eced->name); + free(eced); +} + +static void +_ecore_con_eet_raw_data_free(void *data) +{ + Ecore_Con_Eet_Raw_Data *eced = data; + + eina_stringshare_del(eced->name); + free(eced); +} +static void +_ecore_con_eet_reply_cleanup(Ecore_Con_Reply *n) +{ + if (n->buffer_handler) free(n->buffer); + n->buffer = NULL; + n->buffer_handler = NULL; + free(n->buffer_section); + n->buffer_section = NULL; +} + +typedef struct _Ecore_Con_Eet_Protocol Ecore_Con_Eet_Protocol; +struct _Ecore_Con_Eet_Protocol { + const char *type; + void *data; +}; + +static const char * +_ecore_con_eet_data_type_get(const void *data, Eina_Bool *unknow EINA_UNUSED) +{ + const Ecore_Con_Eet_Protocol *p = data; + + return p->type; +} + +static Eina_Bool +_ecore_con_eet_data_type_set(const char *type, void *data, Eina_Bool unknow EINA_UNUSED) +{ + Ecore_Con_Eet_Protocol *p = data; + + p->type = type; + return EINA_TRUE; +} + +static void +_ecore_con_eet_data_descriptor_setup(Ecore_Con_Eet *ece) +{ + Eet_Data_Descriptor_Class eddc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Ecore_Con_Eet_Protocol); + ece->edd = eet_data_descriptor_stream_new(&eddc); + + eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + eddc.func.type_get = _ecore_con_eet_data_type_get; + eddc.func.type_set = _ecore_con_eet_data_type_set; + ece->matching = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_VARIANT(ece->edd, Ecore_Con_Eet_Protocol, "data", data, type, ece->matching); +} + +/* Dealing with a server listening to connection */ +static Eina_Bool +_ecore_con_eet_read_cb(const void *eet_data, size_t size, void *user_data) +{ + Ecore_Con_Reply *n = user_data; + Ecore_Con_Eet_Protocol *protocol; + Ecore_Con_Eet_Data *cb; + + protocol = eet_data_descriptor_decode(n->ece->edd, eet_data, size); + if (!protocol) return EINA_TRUE; + + cb = eina_hash_find(n->ece->data_callbacks, protocol->type); + if (!cb) return EINA_TRUE; /* Should I report unknow protocol communication ? */ + + cb->func((void*)cb->data, n, cb->name, protocol->data); + + eina_stringshare_del(protocol->type); + free(protocol); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_server_write_cb(const void *data, size_t size, void *user_data) +{ + Ecore_Con_Reply *n = user_data; + + if (ecore_con_client_send(n->client, data, size) != (int) size) + return EINA_FALSE; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_client_write_cb(const void *data, size_t size, void *user_data) +{ + Ecore_Con_Reply *n = user_data; + + if (ecore_con_server_send(n->ece->server, data, size) != (int) size) + return EINA_FALSE; + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_server_connected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Add *ev) +{ + Ecore_Con_Eet_Client *ecec; + Eina_List *ll; + Ecore_Con_Eet *r = data; + Ecore_Con_Reply *n; + + if (ecore_con_client_server_get(ev->client) != r->server) + return EINA_TRUE; + + n = calloc(1, sizeof (Ecore_Con_Reply)); + if (!n) return EINA_TRUE; + + n->client = ev->client; + n->ece = r; + n->econn = eet_connection_new(_ecore_con_eet_read_cb, _ecore_con_eet_server_write_cb, n); + ecore_con_client_data_set(n->client, n); + + EINA_LIST_FOREACH(r->u.server.client_connect_callbacks, ll, ecec) + if (!ecec->func((void*) ecec->data, n, n->client)) + { + eet_connection_close(n->econn, NULL); + free(n); + return EINA_TRUE; + } + + r->u.server.connections = eina_list_append(r->u.server.connections, n); + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_server_disconnected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Del *ev) +{ + Ecore_Con_Eet *r = data; + Ecore_Con_Reply *n; + Eina_List *l; + + if (ecore_con_client_server_get(ev->client) != r->server) + return EINA_TRUE; + + EINA_LIST_FOREACH(r->u.server.connections, l, n) + if (n->client == ev->client) + { + Ecore_Con_Eet_Client *ecec; + Eina_List *ll; + + EINA_LIST_FOREACH(r->u.server.client_disconnect_callbacks, ll, ecec) + ecec->func((void*) ecec->data, n, n->client); + + eet_connection_close(n->econn, NULL); + free(n); + r->u.server.connections = eina_list_remove_list(r->u.server.connections, l); + return EINA_TRUE; + } + + return EINA_TRUE; +} + +static void +_ecore_con_eet_raw_data_push(Ecore_Con_Reply *n, void *data, int size) +{ + if (n->buffer_handler) + memcpy(n->buffer + n->buffer_current, data, size); + n->buffer_current += size; + + if (n->buffer_current == n->buffer_length) + { + if (n->buffer_handler) + n->buffer_handler->func((void*) n->buffer_handler->data, n, n->buffer_handler->name, n->buffer_section, n->buffer, n->buffer_length); + _ecore_con_eet_reply_cleanup(n); + } +} + +static void +_ecore_con_eet_data(Ecore_Con_Reply *n, void *data, unsigned int size) +{ + /* FIXME: Enforce detection of attack and kill connection on that case */ + if (n->buffer) + { + if (n->buffer_current + size > n->buffer_length) + { + _ecore_con_eet_reply_cleanup(n); + return ; + } + + _ecore_con_eet_raw_data_push(n, data, size); + return ; + } + else if (eet_connection_empty(n->econn) && size > (int) (4 * sizeof (unsigned int) + 2)) + { + unsigned int *tmp = data; + size -= 4 * sizeof (unsigned int) + 2; + + if (ntohl(tmp[0]) == ECORE_CON_EET_RAW_MAGIC) + { + unsigned int protocol_length = ntohl(tmp[1]); + unsigned int section_length = ntohl(tmp[2]); + unsigned int data_length = ntohl(tmp[3]); + + if (protocol_length > 1 && section_length > 1 && protocol_length + section_length <= size && data_length < 10 * 1024 * 1024) + { + char *buffer = (char*) &tmp[4]; + char *protocol; + char *section; + + protocol = buffer; + section = buffer + protocol_length; + + if (protocol[protocol_length - 1] == '\0' && + section[section_length - 1] == '\0') + { + size -= protocol_length + section_length; + buffer = section + section_length; + + n->buffer_handler = eina_hash_find(n->ece->raw_data_callbacks, protocol); + n->buffer_section = strdup(section); + n->buffer_length = data_length; + n->buffer_current = 0; + if (n->buffer_handler) + n->buffer = malloc(sizeof (data_length)); + else + n->buffer = (void*) 1; + if (n->buffer) + { + _ecore_con_eet_raw_data_push(n, buffer, size); + return ; + } + _ecore_con_eet_reply_cleanup(n); + + size += protocol_length + section_length; + } + } + } + + size += 4 * sizeof (unsigned int) + 2; + } + + eet_connection_received(n->econn, data, size); +} + +static Eina_Bool +_ecore_con_eet_server_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Client_Data *ev) +{ + Ecore_Con_Eet *r = data; + Ecore_Con_Reply *n; + + if (ecore_con_client_server_get(ev->client) != r->server) + return EINA_TRUE; + + n = ecore_con_client_data_get(ev->client); + + _ecore_con_eet_data(n, ev->data, ev->size); + + return EINA_TRUE; +} + +/* Dealing connection to a server */ + +static Eina_Bool +_ecore_con_eet_client_connected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Add *ev) +{ + Ecore_Con_Eet_Server *eces; + Ecore_Con_Eet *r = data; + Ecore_Con_Reply *n; + Eina_List *ll; + + /* Client did connect */ + if (r->server != ev->server) return EINA_TRUE; + if (r->u.client.r) return EINA_TRUE; + + n = calloc(1, sizeof (Ecore_Con_Reply)); + if (!n) return EINA_TRUE; + + n->client = NULL; + n->ece = r; + n->econn = eet_connection_new(_ecore_con_eet_read_cb, _ecore_con_eet_client_write_cb, n); + + EINA_LIST_FOREACH(r->u.client.server_connect_callbacks, ll, eces) + if (!eces->func((void*) eces->data, n, n->ece->server)) + { + eet_connection_close(n->econn, NULL); + free(n); + return EINA_TRUE; + } + + r->u.client.r = n; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_client_disconnected(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Del *ev) +{ + Ecore_Con_Eet *r = data; + Ecore_Con_Eet_Server *eces; + Eina_List *ll; + + if (r->server != ev->server) return EINA_TRUE; + if (!r->u.client.r) return EINA_TRUE; + + /* Client disconnected */ + EINA_LIST_FOREACH(r->u.client.server_disconnect_callbacks, ll, eces) + eces->func((void*) eces->data, r->u.client.r, r->server); + + eet_connection_close(r->u.client.r->econn, NULL); + free(r->u.client.r); + r->u.client.r = NULL; + + return EINA_TRUE; +} + +static Eina_Bool +_ecore_con_eet_client_data(void *data, int type EINA_UNUSED, Ecore_Con_Event_Server_Data *ev) +{ + Ecore_Con_Eet *r = data; + + if (r->server != ev->server) return EINA_TRUE; + if (!r->u.client.r) return EINA_TRUE; + + /* Got some data */ + _ecore_con_eet_data(r->u.client.r, ev->data, ev->size); + + return EINA_TRUE; +} + +/************** + * Global API * + **************/ + +EAPI Ecore_Con_Eet * +ecore_con_eet_server_new(Ecore_Con_Server *server) +{ + Ecore_Con_Eet *r; + + if (!server) return NULL; + + r = calloc(1, sizeof (Ecore_Con_Eet)); + if (!r) return NULL; + + r->server = server; + r->handler_add = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_ADD, + (Ecore_Event_Handler_Cb)_ecore_con_eet_server_connected, r); + r->handler_del = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, + (Ecore_Event_Handler_Cb)_ecore_con_eet_server_disconnected, r); + r->handler_data = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, + (Ecore_Event_Handler_Cb)_ecore_con_eet_server_data, r); + r->data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_data_free); + r->raw_data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_raw_data_free); + + _ecore_con_eet_data_descriptor_setup(r); + + return r; +} + +EAPI Ecore_Con_Eet * +ecore_con_eet_client_new(Ecore_Con_Server *server) +{ + Ecore_Con_Eet *r; + + if (!server) return NULL; + + r = calloc(1, sizeof (Ecore_Con_Eet)); + if (!r) return NULL; + + r->client = EINA_TRUE; + r->server = server; + r->handler_add = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, + (Ecore_Event_Handler_Cb)_ecore_con_eet_client_connected, r); + r->handler_del = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, + (Ecore_Event_Handler_Cb)_ecore_con_eet_client_disconnected, r); + r->handler_data = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA, + (Ecore_Event_Handler_Cb)_ecore_con_eet_client_data, r); + r->data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_data_free); + r->raw_data_callbacks = eina_hash_stringshared_new(_ecore_con_eet_raw_data_free); + + _ecore_con_eet_data_descriptor_setup(r); + + return r; +} + +EAPI void +ecore_con_eet_server_free(Ecore_Con_Eet *r) +{ + if (!r) return ; + + eet_data_descriptor_free(r->edd); + eet_data_descriptor_free(r->matching); + eina_hash_free(r->data_callbacks); + eina_hash_free(r->raw_data_callbacks); + + if (r->client) + { + Ecore_Con_Eet_Server *s; + + if (r->u.client.r) + { + _ecore_con_eet_reply_cleanup(r->u.client.r); + eet_connection_close(r->u.client.r->econn, NULL); + free(r->u.client.r); + } + EINA_LIST_FREE(r->u.client.server_connect_callbacks, s) + free(s); + EINA_LIST_FREE(r->u.client.server_disconnect_callbacks, s) + free(s); + } + else + { + Ecore_Con_Reply *n; + Ecore_Con_Eet_Client *c; + + EINA_LIST_FREE(r->u.server.connections, n) + { + _ecore_con_eet_reply_cleanup(n); + eet_connection_close(n->econn, NULL); + free(n); + } + EINA_LIST_FREE(r->u.server.client_connect_callbacks, c) + free(c); + EINA_LIST_FREE(r->u.server.client_disconnect_callbacks, c) + free(c); + } + + ecore_event_handler_del(r->handler_add); + ecore_event_handler_del(r->handler_del); + ecore_event_handler_del(r->handler_data); + free(r); +} + +EAPI void +ecore_con_eet_register(Ecore_Con_Eet *ece, const char *name, Eet_Data_Descriptor *edd) +{ + if (!ece) return ; + + EET_DATA_DESCRIPTOR_ADD_MAPPING(ece->matching, name, edd); +} + +EAPI void +ecore_con_eet_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Data_Cb func, const void *data) +{ + Ecore_Con_Eet_Data *eced; + + if (!ece) return ; + + eced = calloc(1, sizeof (Ecore_Con_Eet_Data));; + if (!eced) return ; + + eced->func = func; + eced->data = data; + eced->name = eina_stringshare_add(name); + + eina_hash_direct_add(ece->data_callbacks, eced->name, eced); +} + +EAPI void +ecore_con_eet_data_callback_del(Ecore_Con_Eet *ece, const char *name) +{ + if (!ece) return ; + eina_hash_del(ece->data_callbacks, name, NULL); +} + +EAPI void +ecore_con_eet_raw_data_callback_add(Ecore_Con_Eet *ece, const char *name, Ecore_Con_Eet_Raw_Data_Cb func, const void *data) +{ + Ecore_Con_Eet_Raw_Data *eced; + + if (!ece) return ; + + eced = calloc(1, sizeof (Ecore_Con_Eet_Raw_Data));; + if (!eced) return ; + + eced->func = func; + eced->data = data; + eced->name = eina_stringshare_add(name); + + eina_hash_direct_add(ece->raw_data_callbacks, eced->name, eced); +} + +EAPI void +ecore_con_eet_raw_data_callback_del(Ecore_Con_Eet *ece, const char *name) +{ + if (!ece) return ; + + if (ece->client && ece->u.client.r->buffer_handler && !strcmp(ece->u.client.r->buffer_handler->name, name)) + { + ece->u.client.r->buffer_handler = NULL; + free(ece->u.client.r->buffer); + ece->u.client.r->buffer = (void*) 1; + } + eina_hash_del(ece->raw_data_callbacks, name, NULL); +} + +EAPI void +ecore_con_eet_client_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data) +{ + Ecore_Con_Eet_Client *c; + + if (!ece || !func) return ; + + c = calloc(1, sizeof (Ecore_Con_Eet_Client)); + if (!c) return ; + + c->func = func; + c->data = data; + + ece->u.server.client_connect_callbacks = eina_list_append(ece->u.server.client_connect_callbacks, c); +} + +EAPI void +ecore_con_eet_client_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data) +{ + Ecore_Con_Eet_Client *c; + Eina_List *l; + + if (!ece || !func) return ; + + EINA_LIST_FOREACH(ece->u.server.client_connect_callbacks, l, c) + if (c->func == func && c->data == data) + { + ece->u.server.client_connect_callbacks = eina_list_remove_list(ece->u.server.client_connect_callbacks, l); + free(c); + return ; + } +} + +EAPI void +ecore_con_eet_client_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data) +{ + Ecore_Con_Eet_Client *c; + + if (!ece || !func) return ; + + c = calloc(1, sizeof (Ecore_Con_Eet_Client)); + if (!c) return ; + + c->func = func; + c->data = data; + + ece->u.server.client_connect_callbacks = eina_list_append(ece->u.server.client_disconnect_callbacks, c); +} + +EAPI void +ecore_con_eet_client_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Client_Cb func, const void *data) +{ + Ecore_Con_Eet_Client *c; + Eina_List *l; + + if (!ece || !func) return ; + + EINA_LIST_FOREACH(ece->u.server.client_disconnect_callbacks, l, c) + if (c->func == func && c->data == data) + { + ece->u.server.client_disconnect_callbacks = eina_list_remove_list(ece->u.server.client_disconnect_callbacks, + l); + free(c); + return ; + } +} + +EAPI void +ecore_con_eet_server_connect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data) +{ + Ecore_Con_Eet_Server *s; + + if (!ece || !func) return ; + + s = calloc(1, sizeof (Ecore_Con_Eet_Server)); + if (!s) return ; + + s->func = func; + s->data = data; + + ece->u.client.server_connect_callbacks = eina_list_append(ece->u.client.server_connect_callbacks, s); +} + +EAPI void +ecore_con_eet_server_connect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data) +{ + Ecore_Con_Eet_Server *s; + Eina_List *l; + + if (!ece || !func) return ; + + EINA_LIST_FOREACH(ece->u.client.server_connect_callbacks, l, s) + if (s->func == func && s->data == data) + { + ece->u.client.server_connect_callbacks = eina_list_remove_list(ece->u.client.server_connect_callbacks, l); + free(s); + return ; + } +} + +EAPI void +ecore_con_eet_server_disconnect_callback_add(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data) +{ + Ecore_Con_Eet_Server *s; + + if (!ece || !func) return ; + + s = calloc(1, sizeof (Ecore_Con_Eet_Server)); + if (!s) return ; + + s->func = func; + s->data = data; + + ece->u.client.server_disconnect_callbacks = eina_list_append(ece->u.client.server_disconnect_callbacks, s); +} + +EAPI void +ecore_con_eet_server_disconnect_callback_del(Ecore_Con_Eet *ece, Ecore_Con_Eet_Server_Cb func, const void *data) +{ + Ecore_Con_Eet_Server *s; + Eina_List *l; + + if (!ece || !func) return ; + + EINA_LIST_FOREACH(ece->u.client.server_disconnect_callbacks, l, s) + if (s->func == func && s->data == data) + { + ece->u.client.server_disconnect_callbacks = eina_list_remove_list(ece->u.client.server_disconnect_callbacks, l); + free(s); + return ; + } +} + +EAPI void +ecore_con_eet_data_set(Ecore_Con_Eet *ece, const void *data) +{ + if (!ece) return; + + ece->data = data; +} + +EAPI void * +ecore_con_eet_data_get(Ecore_Con_Eet *ece) +{ + if (!ece) return NULL; + return (void*) ece->data; +} + +EAPI Ecore_Con_Eet * +ecore_con_eet_reply(Ecore_Con_Reply *reply) +{ + if (!reply) return NULL; + return reply->ece; +} + +EAPI void +ecore_con_eet_send(Ecore_Con_Reply *reply, const char *name, void *value) +{ + Ecore_Con_Eet_Protocol protocol; + + if (!reply) return ; + + protocol.type = name; + protocol.data = value; + + eet_connection_send(reply->econn, reply->ece->edd, &protocol, NULL); +} + +EAPI void +ecore_con_eet_raw_send(Ecore_Con_Reply *reply, const char *protocol_name, const char *section, void *value, unsigned int length) +{ + unsigned int protocol[4]; + unsigned int protocol_length; + unsigned int section_length; + unsigned int size; + char *tmp; + + if (!reply) return ; + if (!protocol_name) return ; + if (!section) return ; + + protocol_length = strlen(protocol_name) + 1; + if (protocol_length == 1) return ; + section_length = strlen(section) + 1; + + protocol[0] = htonl(ECORE_CON_EET_RAW_MAGIC); + protocol[1] = htonl(protocol_length); + protocol[2] = htonl(section_length); + protocol[3] = htonl(length); + + size = sizeof (protocol) + protocol_length + section_length; + tmp = alloca(size); + memcpy(tmp, protocol, sizeof (protocol)); + memcpy(tmp + sizeof (protocol), protocol, protocol_length); + memcpy(tmp + sizeof (protocol) + protocol_length, section, section_length); + + if (reply->client) + { + ecore_con_client_send(reply->client, tmp, size); + ecore_con_client_send(reply->client, value, length); + } + else + { + ecore_con_server_send(reply->ece->server, tmp, size); + ecore_con_server_send(reply->ece->server, value, length); + } +} + 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..f51eb26 --- /dev/null +++ b/src/lib/ecore_con/ecore_con_info.c @@ -0,0 +1,472 @@ +/* + * 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); +} + +Eina_Bool +_ecore_fd_close_on_exec(int fd) +{ +#ifdef HAVE_EXECVP + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + return EINA_FALSE; + + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) + return EINA_FALSE; + return EINA_TRUE; +#else + (void) fd; + return EINA_FALSE; +#endif +} + +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; + } + + _ecore_fd_close_on_exec(fd[0]); + _ecore_fd_close_on_exec(fd[1]); + + 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 index d5d9258..26e9970 100644 --- a/src/lib/ecore_con/ecore_con_private.h +++ b/src/lib/ecore_con/ecore_con_private.h @@ -1,8 +1,8 @@ #ifndef _ECORE_CON_PRIVATE_H #define _ECORE_CON_PRIVATE_H +#include "ecore_private.h" #include "Ecore_Con.h" -#include "Ecore_Data.h" #define ECORE_MAGIC_CON_SERVER 0x77665544 #define ECORE_MAGIC_CON_CLIENT 0x77556677 @@ -10,9 +10,12 @@ #define ECORE_CON_TYPE 0x0f #define ECORE_CON_SSL 0xf0 +#define ECORE_CON_SUPER_SSL 0xf00 -#if USE_OPENSSL -#include +#if USE_GNUTLS +# include +#elif USE_OPENSSL +# include #endif #ifdef HAVE_CURL #include @@ -20,75 +23,377 @@ #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 *server; - void *data; + int fd; + Ecore_Con_Server *host_server; + void *data; Ecore_Fd_Handler *fd_handler; - int buf_size; - int buf_offset; - unsigned char *buf; - char *ip; - int event_count; - char dead : 1; - char delete_me : 1; + 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; + int fd; + Ecore_Con_Type type; + char *name; + int port; + char *path; + void *data; Ecore_Fd_Handler *fd_handler; - Ecore_List *clients; - int write_buf_size; - int write_buf_offset; - unsigned char *write_buf; - int event_count; - int client_limit; - pid_t ppid; -#if USE_OPENSSL - SSL_CTX *ssl_ctx; - SSL *ssl; + 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 - char *ip; - char dead : 1; - char created : 1; - char connecting : 1; - char reject_excess_clients : 1; - char delete_me : 1; }; #ifdef HAVE_CURL struct _Ecore_Con_Url { ECORE_MAGIC; - CURL *curl_easy; + CURL *curl_easy; struct curl_slist *headers; - char *url; + 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; - Ecore_Con_Url_Time condition; - time_t time; - void *data; + int received; + int write_fd; - Ecore_Fd_Handler *fd_handler; - int fd; - int flags; + unsigned int event_count; + Eina_Bool dead : 1; + Eina_Bool multi : 1; +}; +#endif - int received; - int write_fd; +struct _Ecore_Con_Info +{ + unsigned int size; + struct addrinfo info; + char ip[NI_MAXHOST]; + char service[NI_MAXSERV]; +}; - unsigned char active : 1; +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_dns.c */ -int ecore_con_dns_init(void); -int ecore_con_dns_shutdown(void); +/* 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..1027dbb --- /dev/null +++ b/src/lib/ecore_con/ecore_con_ssl.c @@ -0,0 +1,2115 @@ +#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: + svr->ssl_prepared = EINA_TRUE; + 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")); + + svr->ssl_prepared = EINA_TRUE; + 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); + fp = NULL; + 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); + fp = NULL; + 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 index 7527f58..419cfca 100644 --- a/src/lib/ecore_con/ecore_con_url.c +++ b/src/lib/ecore_con/ecore_con_url.c @@ -1,345 +1,425 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -/* * For info on how to use libcurl, see: * http://curl.haxx.se/libcurl/c/libcurl-tutorial.html */ /* - * Brief usage: - * 1. Create an Ecore_Con_Url object - * 2. Register to receive the ECORE_CON_EVENT_URL_COMPLETE event - * (and optionally the ECORE_CON_EVENT_URL_DATA event to receive - * the response, e.g. for HTTP/FTP downloads) - * 3. Set the URL with ecore_con_url_url_set(...); - * 4. Perform the operation with ecore_con_url_send(...); - * - * Note that it is good to reuse 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. - * - * Example Usage 1 (HTTP GET): - * ecore_con_url_url_set(url_con, "http://www.google.com"); - * ecore_con_url_send(url_con, NULL, 0, NULL); - * - * Example usage 2 (HTTP POST): - * ecore_con_url_url_set(url_con, "http://www.example.com/post_handler.cgi"); - * ecore_con_url_send(url_con, data, data_length, "multipart/form-data"); - * - * Example Usage 3 (FTP download): - * ecore_con_url_url_set(url_con, "ftp://ftp.example.com/pub/myfile"); - * ecore_con_url_send(url_con, NULL, 0, NULL); - * - * Example Usage 4 (FTP upload as ftp://ftp.example.com/file): - * ecore_con_url_url_set(url_con, "ftp://ftp.example.com"); - * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass", NULL); - * - * Example Usage 5 (FTP upload as ftp://ftp.example.com/dir/file): - * ecore_con_url_url_set(url_con, "ftp://ftp.example.com"); - * ecore_con_url_ftp_upload(url_con, "/tmp/file", "user", "pass","dir"); - * - * FIXME: Support more CURL features: Authentication, Progress callbacks and more... + * FIXME: Support more CURL features... */ -#include "Ecore.h" -#include "ecore_private.h" -#include "Ecore_Con.h" -#include "ecore_con_private.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include #include #include #include +#include -/** - * @defgroup Ecore_Con_Url_Group Ecore URL Connection Functions - * - * Utility functions that set up, use and shut down the Ecore URL - * Connection library. - * FIXME: write detailed description - */ +#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 int _ecore_con_url_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_con_url_perform(Ecore_Con_Url *url_con); -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(void *data __UNUSED__, void *ev); -static int _ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match); - -static Ecore_Idler *_fd_idler_handler = NULL; -static Ecore_List *_url_con_list = NULL; -static CURLM *curlm = NULL; -static fd_set _current_fd_set; -static int init_count = 0; - -struct _Ecore_Con_Url_Event -{ - int type; - void *ev; -}; -typedef struct _Ecore_Con_Url_Event Ecore_Con_Url_Event; - -static int -_url_complete_idler_cb(void *data) -{ - Ecore_Con_Url_Event *lev; - - lev = data; - - ecore_event_add(lev->type, lev->ev, _ecore_con_event_url_free, NULL); - free(lev); - - return 0; -} - -static void -_url_complete_push_event(int type, void *ev) -{ - Ecore_Con_Url_Event *lev; - - lev = malloc(sizeof(Ecore_Con_Url_Event)); - lev->type = type; - lev->ev = ev; - - ecore_idler_add(_url_complete_idler_cb, lev); -} - +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; +Ecore_Idler *_curl_idler; #endif /** - * Initialises the Ecore_Con_Url library. - * @return Number of times the library has been initialised without being - * shut down. - * @ingroup Ecore_Con_Url_Group + * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions + * + * @{ */ + EAPI int ecore_con_url_init(void) { #ifdef HAVE_CURL - if (!ECORE_CON_EVENT_URL_DATA) - { - 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(); - } + 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(); - if (!_url_con_list) + // curl_global_init() is not thread safe! + if (curl_global_init(CURL_GLOBAL_ALL)) return --_init_count; + + _curlm = curl_multi_init(); + if (!_curlm) { - _url_con_list = ecore_list_new(); - if (!_url_con_list) return 0; + curl_global_cleanup(); + return --_init_count; } - if (!curlm) - { - FD_ZERO(&_current_fd_set); - if (curl_global_init(CURL_GLOBAL_NOTHING)) - { - ecore_list_destroy(_url_con_list); - _url_con_list = NULL; - return 0; - } + curl_multi_timeout(_curlm, &ms); + if (ms >= CURL_MIN_TIMEOUT || ms <= 0) ms = CURL_MIN_TIMEOUT; - curlm = curl_multi_init(); - if (!curlm) - { - ecore_list_destroy(_url_con_list); - _url_con_list = NULL; - return 0; - } - } - init_count++; - return 1; + _curl_timer = ecore_timer_add((double)ms / 1000, _ecore_con_url_timer, NULL); + ecore_timer_freeze(_curl_timer); + _curl_idler = NULL; + + return _init_count; #else return 0; #endif } -/** - * Shuts down the Ecore_Con_Url library. - * @return Number of calls that still uses Ecore_Con_Url - * @ingroup Ecore_Con_Url_Group - */ 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 (!init_count) - return 0; - - init_count--; - if (_url_con_list) + if (_curl_timer) { - if (!ecore_list_empty_is(_url_con_list)) - { - Ecore_Con_Url *url_con; - while ((url_con = ecore_list_first(_url_con_list))) - { - ecore_con_url_destroy(url_con); - } - } - ecore_list_destroy(_url_con_list); - _url_con_list = NULL; + ecore_timer_del(_curl_timer); + _curl_timer = NULL; } - if (curlm) + if (_curl_idler) ecore_idler_del(_curl_idler); + _curl_idler = 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_multi_cleanup(_curlm); + _curlm = NULL; } - curl_global_cleanup(); + return 0; #endif return 1; } -/** - * Creates and initializes a new Ecore_Con_Url. - * @return NULL on error, a new Ecore_Con_Url on success. - * @ingroup Ecore_Con_Url_Group - */ +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; + if (!_init_count) + return NULL; url_con = calloc(1, sizeof(Ecore_Con_Url)); - if (!url_con) return NULL; + 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; + free(url_con); + return NULL; } ECORE_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL); - ecore_con_url_url_set(url_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_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_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, FALSE); + 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_FORBID_REUSE, 1); curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30); - curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEOUT, 300); curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate"); + 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; - url_con->fd = -1; - url_con->write_fd = -1; + 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 } -/** - * Frees the Ecore_Con_Url. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ EAPI void -ecore_con_url_destroy(Ecore_Con_Url *url_con) +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_destroy"); - return; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_free"); + return; } - ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE); - if (url_con->fd_handler) - { - ecore_main_fd_handler_del(url_con->fd_handler); - url_con->fd = -1; - } if (url_con->curl_easy) { - if (url_con->active) - { - if (ecore_list_find(_url_con_list, ecore_direct_compare, url_con) == url_con) - ecore_list_remove(_url_con_list); - url_con->active = 0; - - curl_multi_remove_handle(curlm, url_con->curl_easy); - } - curl_easy_cleanup(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); - free(url_con->url); + 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; - url_con = NULL; + (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 } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ 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 0; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_url_set"); + return EINA_FALSE; } - if (url_con->active) return 0; + if (url_con->dead) return EINA_FALSE; + eina_stringshare_replace(&url_con->url, url); - free(url_con->url); - url_con->url = NULL; - if (url) - url_con->url = strdup(url); - curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, url_con->url); - return 1; + 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 0; - url_con = NULL; - url = NULL; + return EINA_FALSE; + (void)url; + (void)url_con; #endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ 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; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_set"); + return; } url_con->data = data; @@ -350,19 +430,65 @@ ecore_con_url_data_set(Ecore_Con_Url *url_con, void *data) #endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ +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; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_get"); + return NULL; } return url_con->data; @@ -372,287 +498,886 @@ ecore_con_url_data_get(Ecore_Con_Url *url_con) #endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ EAPI void -ecore_con_url_time(Ecore_Con_Url *url_con, Ecore_Con_Url_Time condition, time_t tm) +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; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_time"); + return; } - url_con->condition = condition; - url_con->time = tm; + if (url_con->dead) return; + url_con->time_condition = condition; + url_con->timestamp = timestamp; #else return; - url_con = NULL; - condition = 0; - tm = 0; + (void)url_con; + (void)condition; + (void)timestamp; #endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ 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 ; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_set"); + return; } + + if (url_con->dead) return; url_con->write_fd = fd; -#endif +#else + return; + (void)url_con; + (void)fd; +#endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ 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; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_received_bytes_get"); + return -1; } return url_con->received; -#endif +#else return 0; + (void)url_con; +#endif } -/** - * FIXME: To be documented. - * @return FIXME: To be documented. - * @ingroup Ecore_Con_Url_Group - */ -EAPI int -ecore_con_url_send(Ecore_Con_Url *url_con, void *data, size_t length, char *content_type) +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 - char tmp[256]; + 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 0; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_send"); + return EINA_FALSE; } - if (url_con->active) return 0; - if (!url_con->url) return 0; + 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 (data) + if ((mode == MODE_POST) || (mode == MODE_AUTO)) { - curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, data); - curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length); - - if (content_type && (strlen(content_type) < 200)) - { - sprintf(tmp, "Content-type: %s", content_type); - url_con->headers = curl_slist_append(url_con->headers, tmp); - } - sprintf(tmp, "Content-length: %d", length); - url_con->headers = curl_slist_append(url_con->headers, tmp); + 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->condition) + switch (url_con->time_condition) { case ECORE_CON_URL_TIME_NONE: - curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE); - break; + 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, url_con->time); - break; + 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, url_con->time); - break; - case ECORE_CON_URL_TIME_LASTMOD: - curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, CURL_TIMECOND_LASTMOD); - curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE, url_con->time); - break; + 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 0; - url_con = NULL; - data = NULL; - length = 0; - content_type = NULL; + return EINA_FALSE; + (void)url_con; + (void)mode; + (void)data; + (void)length; + (void)content_type; #endif } -/** - * Makes a FTP upload - * @return FIXME: To be more documented. - * @ingroup Ecore_Con_Url_Group - */ -EAPI int -ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, char *filename, char *user, char *pass, char *upload_dir) +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 0; - } - - if (url_con->active) return 0; - if (!url_con->url) return 0; - if (filename) - { - if (stat(filename, &file_info)) return 0; - fd = fopen(filename, "rb"); - if (upload_dir) - snprintf(url, sizeof(url), "ftp://%s/%s/%s", url_con->url, upload_dir, basename(filename)); - else - snprintf(url, sizeof(url), "ftp://%s/%s", url_con->url, basename(filename)); - snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass); - 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_USERPWD, userpwd); - curl_easy_setopt(url_con->curl_easy, CURLOPT_UPLOAD, 1); - curl_easy_setopt(url_con->curl_easy, CURLOPT_READFUNCTION, _ecore_con_url_read_cb); - curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd); - ecore_con_url_url_set(url_con, url); - - return _ecore_con_url_perform(url_con); + 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 - return 0; + 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 0; - url_con = NULL; - filename = NULL; - user = NULL; - pass = NULL; - upload_dir = NULL; -#endif + return EINA_FALSE; + (void)url_con; + (void)filename; + (void)user; + (void)pass; + (void)upload_dir; +#endif } -/** - * Enable or disable libcurl verbose output, useful for debug - * @return FIXME: To be more documented. - * @ingroup Ecore_Con_Url_Group - */ EAPI void -ecore_con_url_verbose_set(Ecore_Con_Url *url_con, int verbose) +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_verbose_set"); - return; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_cookies_file_add"); + return; } - - if (url_con->active) return; - if (!url_con->url) return; - if (verbose == TRUE) - curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, 1); - else - curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, 0); + + 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 } /** - * Enable or disable EPSV extension - * @return FIXME: To be more documented. - * @ingroup Ecore_Con_Url_Group + * 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_ftp_use_epsv_set(Ecore_Con_Url *url_con, int use_epsv) +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_ftp_use_epsv_set"); - return; + ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, + "ecore_con_url_ssl_verify_peer_set"); + return; } - - if (url_con->active) return; - if (!url_con->url) return; - if (use_epsv == TRUE) - curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, 1); - else - curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, 0); + + 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 -static int -_ecore_con_url_suspend_fd_handler(void) + 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) { - Ecore_Con_Url *url_con; - int deleted = 0; +#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_list) - return 0; + 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; + } - ecore_list_first_goto(_url_con_list); - while ((url_con = ecore_list_current(_url_con_list))) + 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) { - if (url_con->active && url_con->fd_handler) - { - ecore_main_fd_handler_del(url_con->fd_handler); - url_con->fd_handler = NULL; - deleted++; - } - ecore_list_next(_url_con_list); + ERR("Proxy type should be socks5 and above"); + return EINA_FALSE; } - return deleted; + 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 } -static int -_ecore_con_url_restart_fd_handler(void) +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_Url *url_con; - int activated = 0; + Ecore_Con_Event_Url_Complete *e; + int status = url_con->status; - if (!_url_con_list) - return 0; + e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete)); + if (!e) return; - ecore_list_first_goto(_url_con_list); - while ((url_con = ecore_list_current(_url_con_list))) + if (!curlmsg) { - if (url_con->fd_handler == NULL - && url_con->fd != -1) - { - url_con->fd_handler = ecore_main_fd_handler_add(url_con->fd, - url_con->flags, - _ecore_con_url_fd_handler, - NULL, NULL, NULL); - activated++; - } - ecore_list_next(_url_con_list); + ERR("Event completed without CURL message handle. Shouldn't happen"); } + else if ((curlmsg->msg == CURLMSG_DONE) && + (curlmsg->data.result == CURLE_OPERATION_TIMEDOUT) && + (!curlmsg->easy_handle)) + { + /* easy_handle is set to NULL on timeout messages */ + status = 408; /* Request Timeout */ + } + else if (curlmsg->data.result == CURLE_OK) + { + if (!status) + { + _ecore_con_url_status_get(url_con); + status = url_con->status; + } + } + else + { + ERR("Curl message have errors: %d (%s)", + curlmsg->data.result, curl_easy_strerror(curlmsg->data.result)); + } + + e->status = status; + e->url_con = url_con; - return activated; + 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; + CURLMsg timeout_msg; + + 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; + + timeout_msg.msg = CURLMSG_DONE; + timeout_msg.easy_handle = NULL; + timeout_msg.data.result = CURLE_OPERATION_TIMEDOUT; + + _ecore_con_url_event_url_complete(url_con, &timeout_msg); + return ECORE_CALLBACK_CANCEL; } static size_t @@ -664,266 +1389,288 @@ _ecore_con_url_data_cb(void *buffer, size_t size, size_t nitems, void *userp) url_con = (Ecore_Con_Url *)userp; - if (!url_con) return -1; + 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; + 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); - ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, - _ecore_con_event_url_free, NULL); - } + 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; - } - } + 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; } -#define ECORE_CON_URL_TRANSMISSION(Transmit, Event, Url_con, Total, Now) \ -{ \ - Ecore_Con_Event_Url_Progress *e; \ - if ((Total != 0) || (Now != 0)) \ - { \ - e = calloc(1, sizeof(Ecore_Con_Event_Url_Progress)); \ - if (e) \ - { \ - e->url_con = url_con; \ - e->total = Total; \ - e->now = Now; \ - ecore_event_add(Event, e, _ecore_con_event_url_free, NULL); \ - } \ - } \ +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; + Ecore_Con_Event_Url_Progress *e; + Ecore_Con_Url *url_con; url_con = clientp; - e = calloc(1, sizeof(Ecore_Con_Event_Url_Progress)); + 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; - ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, _ecore_con_event_url_free, NULL); + 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 +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) || (retcode < nitems)) { - fclose((FILE*)stream); - return 0; - } - fprintf(stderr, "*** We read %d bytes from file\n", retcode); + + 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 int -_ecore_con_url_perform(Ecore_Con_Url *url_con) +static void +_ecore_con_url_info_read(void) { - fd_set read_set, write_set, exc_set; - double start; - int fd_max; - int fd; - int flags; - int still_running; - int completed_immediately = 0; - - ecore_list_append(_url_con_list, url_con); - - start = ecore_time_get(); - url_con->active = 1; - curl_multi_add_handle(curlm, url_con->curl_easy); - /* This one can't be stopped, or the download never start. */ - while (curl_multi_perform(curlm, &still_running) == CURLM_CALL_MULTI_PERFORM); - - completed_immediately = _ecore_con_url_process_completed_jobs(url_con); - - if (!completed_immediately) - { - /* url_con still active -- set up an fd_handler */ - FD_ZERO(&read_set); - FD_ZERO(&write_set); - FD_ZERO(&exc_set); - - /* Stupid curl, why can't I get the fd to the current added job? */ - curl_multi_fdset(curlm, &read_set, &write_set, &exc_set, &fd_max); - for (fd = 0; fd <= fd_max; fd++) - { - if (!FD_ISSET(fd, &_current_fd_set)) - { - 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) - { - FD_SET(fd, &_current_fd_set); - url_con->fd = fd; - url_con->flags = flags; - url_con->fd_handler = ecore_main_fd_handler_add(fd, flags, - _ecore_con_url_fd_handler, - NULL, NULL, NULL); - break; - } - } - } - if (!url_con->fd_handler) - { - /* Failed to set up an fd_handler */ - curl_multi_remove_handle(curlm, url_con->curl_easy); - url_con->active = 0; - url_con->fd = -1; - return 0; - } + 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); + } + } } +} - return 1; +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 int -_ecore_con_url_idler_handler(void *data) +static Eina_Bool +_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) { - double start; - int done = 1; - int still_running; + Ecore_Fd_Handler *fdh; + long ms; + + EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh); + + curl_multi_timeout(_curlm, &ms); + if (ms >= CURL_MIN_TIMEOUT || ms <= 0) ms = CURL_MIN_TIMEOUT; + + ecore_timer_interval_set(_curl_timer, (double)ms / 1000); + + if (!_curl_timer) + _curl_idler = ecore_idler_add(_ecore_con_url_timer, NULL); - start = ecore_time_get(); - while (curl_multi_perform(curlm, &still_running) == CURLM_CALL_MULTI_PERFORM) - /* make this 1/20th of a second to keep interactivity high */ - if ((ecore_time_get() - start) > 0.2) - { - done = 0; - break; - } + 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; - _ecore_con_url_process_completed_jobs(NULL); + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_ZERO(&exc_set); - if (done) + ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, &fd_max); + if (ret != CURLM_OK) { - _ecore_con_url_restart_fd_handler(); - _fd_idler_handler = NULL; - return 0; + ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret)); + return; } - return 1; + 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 int -_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__) +static Eina_Bool +_ecore_con_url_timer(void *data __UNUSED__) { - _ecore_con_url_suspend_fd_handler(); + Ecore_Fd_Handler *fdh; + int still_running; + CURLMcode ret; - if (_fd_idler_handler == NULL) - _fd_idler_handler = ecore_idler_add(_ecore_con_url_idler_handler, NULL); + EINA_LIST_FREE(_fd_hd_list, fdh) ecore_main_fd_handler_del(fdh); + _ecore_con_url_info_read(); - return 1; + 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 (_curl_idler) ecore_idler_del(_curl_idler); + _curl_idler = NULL; + } + + 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); + if (_curl_idler) ecore_idler_del(_curl_idler); + _curl_idler = NULL; + } + + return ECORE_CALLBACK_RENEW; } -static int -_ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match) +static Eina_Bool +_ecore_con_url_perform(Ecore_Con_Url *url_con) { - Ecore_Con_Url *url_con; - CURLMsg *curlmsg; - int n_remaining; - int job_matched = 0; - - /* Loop jobs and check if any are done */ - while ((curlmsg = curl_multi_info_read(curlm, &n_remaining)) != NULL) - { - if (curlmsg->msg != CURLMSG_DONE) continue; - - /* find the job which is done */ - ecore_list_first_goto(_url_con_list); - while ((url_con = ecore_list_current(_url_con_list))) - { - if (curlmsg->easy_handle == url_con->curl_easy) - { - /* We have found the completed job in our job list */ - if (url_con_to_match && (url_con == url_con_to_match)) { - job_matched = 1; - } - if (url_con->fd != -1) - { - FD_CLR(url_con->fd, &_current_fd_set); - if (url_con->fd_handler) - ecore_main_fd_handler_del(url_con->fd_handler); - url_con->fd = -1; - url_con->fd_handler = NULL; - } - ecore_list_remove(_url_con_list); - url_con->active = 0; - { - Ecore_Con_Event_Url_Complete *e; - e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete)); - if (e) - { - e->url_con = url_con; - - e->status = 0; - curl_easy_getinfo(curlmsg->easy_handle, CURLINFO_RESPONSE_CODE, &e->status); - - _url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e); - } - } - curl_multi_remove_handle(curlm, url_con->curl_easy); - break; - } - ecore_list_next(_url_con_list); - } - } - return job_matched; + 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(void *data __UNUSED__, void *ev) +_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/Makefile.am b/src/lib/ecore_config/Makefile.am index 541233d..c459351 100644 --- a/src/lib/ecore_config/Makefile.am +++ b/src/lib/ecore_config/Makefile.am @@ -10,12 +10,12 @@ AM_CPPFLAGS = \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ -@EVAS_CFLAGS@ @EET_CFLAGS@ +@EVAS_CFLAGS@ \ +@EET_CFLAGS@ \ +@EINA_CFLAGS@ CLEANFILES = $(DB) -if BUILD_ECORE_CONFIG - #DB = system.db #$(DB): Makefile # edb_ed $(top_builddir)/src/lib/ecore_config/$(DB) add /e/theme/name str "winter" @@ -24,65 +24,39 @@ if BUILD_ECORE_CONFIG # 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 -include_HEADERS = \ -Ecore_Config.h -libecore_config_la_LDFLAGS = -version-info @version_info@ +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) -if BUILD_ECORE_IPC - libecore_config_la_SOURCES = \ ecore_config.c \ -ecore_config_ipc_main.c \ -ecore_config_ipc_ecore.c \ ecore_config_util.c \ ecore_config_storage.c \ ecore_config_extra.c \ -ecore_config_db.c \ -ecore_config_private.h +ecore_config_db.c libecore_config_la_LIBADD = \ $(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la \ @EET_LIBS@ \ +@EINA_LIBS@ \ @EVAS_LIBS@ -libecore_config_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la - -else - -libecore_config_la_SOURCES = \ -ecore_config.c \ -ecore_config_util.c \ -ecore_config_storage.c \ -ecore_config_extra.c \ -ecore_config_db.c \ -ecore_config_private.h - -libecore_config_la_LIBADD = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -@EET_LIBS@ \ -@EVAS_LIBS@ +if BUILD_ECORE_IPC -libecore_config_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la +libecore_config_la_SOURCES += \ +ecore_config_ipc_main.c \ +ecore_config_ipc_ecore.c -endif +libecore_config_la_LIBADD += $(top_builddir)/src/lib/ecore_ipc/libecore_ipc.la endif EXTRA_DIST = \ -Ecore_Config.h \ -ecore_config.c \ -ecore_config_ipc_ecore.c \ -ecore_config_ipc_main.c \ ecore_config_ipc.h \ -ecore_config_util.c \ -ecore_config_util.h \ -ecore_config_storage.c - +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 index 275eefd..e81538e 100644 --- a/src/lib/ecore_config/ecore_config.c +++ b/src/lib/ecore_config/ecore_config.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + #include #include #include @@ -11,12 +15,11 @@ #include #include "Ecore_Config.h" -#include "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; @@ -53,8 +56,8 @@ ecore_config_dst(Ecore_Config_Prop * e) Ecore_Config_Listener_List *l; p = NULL; - c = e; t = __ecore_config_bundle_local; + c = t->data; if (!e || !e->key) return NULL; @@ -202,7 +205,7 @@ _ecore_config_int_get(Ecore_Config_Prop *e) /** * 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 + * @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 */ @@ -329,7 +332,7 @@ ecore_config_as_string_get(const char *key) val = NULL; r = NULL; if (!(e = ecore_config_get(key))) - E(0, "no such property, \"%s\"...\n", key); + ERR("no such property, \"%s\"...", key); else { switch (e->type) @@ -384,15 +387,13 @@ ecore_config_bound(Ecore_Config_Prop * e) { if ((e->val < e->lo)) { - E(0, - "ecore_config_bounds(\"%s\",%ld): value out of range; adjusted to %ld...\n", + 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)) { - E(0, - "ecore_config_bounds(\"%s\",%ld): value out of range; adjusted to %ld...\n", + WRN("ecore_config_bounds(\"%s\",%ld): value out of range; adjusted to %ld...", e->key, e->val, e->hi); e->val = e->hi; } @@ -408,14 +409,12 @@ ecore_config_bound(Ecore_Config_Prop * e) if (v != e->val) { if (e->type == ECORE_CONFIG_FLT) - E(0, - "ecore_config_bound(\"%s\"): float value %f not a multiple of %f, adjusted to %f...\n", + 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 - E(0, - "ecore_config_bound(\"%s\"): integer value %ld not a multiple of %ld, adjusted to %ld...\n", + 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; @@ -442,7 +441,6 @@ ecore_config_type_guess(const char *key, const char *val) { Ecore_Config_Prop *p; char *l; - long v; l = NULL; @@ -453,7 +451,7 @@ ecore_config_type_guess(const char *key, const char *val) return ECORE_CONFIG_NIL; if (val[0] == '#') return ECORE_CONFIG_RGB; - v = strtol(val, &l, 10); + strtol(val, &l, 10); if (*l) { float f; @@ -528,7 +526,7 @@ ecore_config_typed_add(const char *key, const void *val, int type) if (!(e = calloc(1, sizeof(Ecore_Config_Prop)))) { - error = ECORE_CONFIG_ERR_OOM; + return ECORE_CONFIG_ERR_OOM; } else if (!(e->key = strdup(key))) { @@ -671,9 +669,8 @@ ecore_config_typed_set(const char *key, const void *val, int type) } else { - E(0, - "ecore_config_typed_set(\"%s\"): ecore_config_typed_val() failed: %d\n", - key, ret); + ERR("ecore_config_typed_set(\"%s\"): ecore_config_typed_val() failed: %d", + key, ret); } return ret; @@ -1151,8 +1148,8 @@ ecore_config_theme_default(const char *key, const char *val) EAPI int ecore_config_struct_create(const char *key) { - printf("WARNING: you are using ecore_config structures. These are very young"); - printf(" and not complete - you have been warned"); + 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); } @@ -1160,13 +1157,13 @@ ecore_config_struct_create(const char *key) static int _ecore_config_struct_append(Ecore_Config_Prop *sct, Ecore_Config_Prop *add) { - Evas_List *l; + Eina_List *l; if (!sct || !add || sct->type != ECORE_CONFIG_SCT) return ECORE_CONFIG_ERR_IGNORED; l = sct->data; - sct->data = evas_list_append(l, add); + sct->data = eina_list_append(l, add); add->parent = sct; return ECORE_CONFIG_ERR_SUCC; @@ -1188,7 +1185,7 @@ _ecore_config_struct_typed_add(const char *key, const char *name, const void *va ret = _ecore_config_struct_append(ecore_config_get(key), ecore_config_get(subkey)); free(subkey); - return ret; + return ret; } /** @@ -1253,7 +1250,7 @@ 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); } @@ -1301,7 +1298,7 @@ EAPI int ecore_config_struct_get(const char *key, void *data) { Ecore_Config_Prop *e, *f; - Evas_List *l; + Eina_List *l; unsigned char *ptr; long argb; @@ -1345,9 +1342,9 @@ ecore_config_struct_get(const char *key, void *data) ptr += sizeof(int); break; default: - printf("ARGH - STRUCT coding not implemented yet\n"); + WRN("ARGH - STRUCT coding not implemented yet"); } - l = evas_list_next(l); + l = eina_list_next(l); } return ECORE_CONFIG_ERR_SUCC; } @@ -1385,13 +1382,13 @@ ecore_config_listen(const char *name, const char *key, if (ret != ECORE_CONFIG_ERR_SUCC) { - E(0, "ecore_config_listen: ecore_config_add(\"%s\") failed: %d\n", - key, ret); + ERR("ecore_config_listen: ecore_config_add(\"%s\") failed: %d", + key, ret); return ret; } if (!(e = ecore_config_get(key))) { - E(0, "ecore_config_listen: list of properties corrupted!?\n"); + ERR("ecore_config_listen: list of properties corrupted!?"); return ECORE_CONFIG_ERR_FAIL; } } @@ -1399,8 +1396,7 @@ ecore_config_listen(const char *name, const char *key, for (l = e->listeners; l; l = l->next) if (!strcmp(l->name, name) || (l->listener == listener)) { - E(1, - "ecore_config_listen: %s is already listening for changes of %s...\n", + ERR("ecore_config_listen: %s is already listening for changes of %s...", name, key); return ECORE_CONFIG_ERR_IGNORED; } @@ -1408,7 +1404,7 @@ ecore_config_listen(const char *name, const char *key, if (!(l = malloc(sizeof(Ecore_Config_Listener_List)))) return ECORE_CONFIG_ERR_OOM; - E(1, "registering listener \"%s\" for \"%s\" (%d)...\n", name, key, e->type); + ERR("registering listener \"%s\" for \"%s\" (%d)...", name, key, e->type); memset(l, 0, sizeof(Ecore_Config_Listener_List)); @@ -1455,7 +1451,7 @@ ecore_config_deaf(const char *name, const char *key, 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)) { @@ -1632,7 +1628,6 @@ ecore_config_init_global(const char *name) char *p; int global; char *buf; - global = 0; if ((p = getenv("HOME"))) { /* debug-only ### FIXME */ @@ -1641,7 +1636,7 @@ ecore_config_init_global(const char *name) snprintf(buf, PATH_MAX, "%s/.ecore/%s/.global", p, name); global = creat(buf, S_IRWXU); - if (global) + if (global >= 0) close(global); free(buf); @@ -1675,6 +1670,13 @@ 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); @@ -1767,7 +1769,7 @@ _ecore_config_system_init_no_load(void) /* set up a simple default path */ ecore_config_string_default("/e/themes/search_path", PACKAGE_DATA_DIR "../ewl/themes"); - + return ECORE_CONFIG_ERR_SUCC; } @@ -1787,7 +1789,7 @@ _ecore_config_system_load(void) { snprintf(buf, PATH_MAX, "%s/.e/config.eet", p); if (ecore_config_file_load(buf) != 0) { - /* even if this file (system.eet) dosen't exist we can + /* 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"); @@ -1831,6 +1833,8 @@ ecore_config_system_shutdown(void) 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; } @@ -1857,7 +1861,7 @@ __ecore_argbstr_to_long(const char *argb, long *v) if(*l) { - E(0, "ecore_config_val: value \"%s\" not a valid hexadecimal RGB value?\n", argb); + ERR("ecore_config_val: value \"%s\" not a valid hexadecimal RGB value?", argb); return NULL; } diff --git a/src/lib/ecore_config/ecore_config_db.c b/src/lib/ecore_config/ecore_config_db.c index 712ebbb..6238958 100644 --- a/src/lib/ecore_config/ecore_config_db.c +++ b/src/lib/ecore_config/ecore_config_db.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + #include #include #include @@ -9,10 +13,11 @@ #include #include +#include + #include "Ecore_Config.h" #include "ecore_config_private.h" #include "ecore_config_util.h" -#include struct _Ecore_Config_DB_File { @@ -24,7 +29,7 @@ _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; @@ -43,7 +48,7 @@ _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; @@ -71,7 +76,7 @@ _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) { @@ -89,7 +94,7 @@ _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) { @@ -113,9 +118,8 @@ _ecore_config_db_read(Ecore_Config_DB_File *db, const char *key) { char *data, *value; int size; - Ecore_Config_Prop *prop; Ecore_Config_Type type; - + data = eet_read(db->ef, (char*)key, &size); if (data) { @@ -139,12 +143,11 @@ _ecore_config_db_read(Ecore_Config_DB_File *db, const char *key) free(data); return 0; } - + type = data[0]; value = data + l + 1; - prop = ecore_config_get(key); - - switch (type) + + switch (type) { case ECORE_CONFIG_INT: case ECORE_CONFIG_BLN: @@ -163,7 +166,7 @@ _ecore_config_db_read(Ecore_Config_DB_File *db, const char *key) 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; } @@ -175,10 +178,10 @@ _ecore_config_db_read(Ecore_Config_DB_File *db, const char *key) ecore_config_typed_set(key, (void *)value, type); break; case ECORE_CONFIG_SCT: - printf("loading struct %s\n", key); + INF("loading struct %s", key); break; default: - E(0, "Type %d not handled\n", type); + WRN("Type %d not handled", type); } free(data); return 1; @@ -192,13 +195,13 @@ _ecore_config_db_key_data_get(Ecore_Config_DB_File *db, const char *key, int *si { char *data; int size; - + data = eet_read(db->ef, (char*)key, &size); if (data) { int l; char *dat; - + if (size <= 2) { free(data); @@ -232,10 +235,10 @@ _ecore_config_db_write(Ecore_Config_DB_File *db, Ecore_Config_Prop *e) char *val = NULL; char *r = NULL; int num; - + prev_locale = setlocale(LC_NUMERIC, "C"); - switch (e->type) + switch (e->type) { case ECORE_CONFIG_INT: esprintf(&val, "%i", _ecore_config_int_get(e)); @@ -246,7 +249,7 @@ _ecore_config_db_write(Ecore_Config_DB_File *db, Ecore_Config_Prop *e) case ECORE_CONFIG_FLT: esprintf(&val, "%16.16f", _ecore_config_float_get(e)); break; - case ECORE_CONFIG_STR: + case ECORE_CONFIG_STR: val = _ecore_config_string_get(e); break; case ECORE_CONFIG_THM: @@ -256,14 +259,14 @@ _ecore_config_db_write(Ecore_Config_DB_File *db, Ecore_Config_Prop *e) val = _ecore_config_argbstr_get(e); break; default: - E(0, "Type %d not handled\n", e->type); + 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); @@ -280,7 +283,7 @@ _ecore_config_db_key_data_set(Ecore_Config_DB_File *db, const char *key, void *d { char *buf; int num; - + num = 1 + 1 + data_size + 1; buf = malloc(num); if (!buf) return; diff --git a/src/lib/ecore_config/ecore_config_extra.c b/src/lib/ecore_config/ecore_config_extra.c index 7981363..a134952 100644 --- a/src/lib/ecore_config/ecore_config_extra.c +++ b/src/lib/ecore_config/ecore_config_extra.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + #include #include #include @@ -7,9 +11,7 @@ #include "Ecore_Config.h" #include "Ecore.h" - -#include "config.h" - +#include "ecore_config_private.h" typedef struct __Ecore_Config_Arg_Callback _Ecore_Config_Arg_Callback; struct __Ecore_Config_Arg_Callback { @@ -401,7 +403,7 @@ ecore_config_theme_search_path_get(void) * should be called @b after @ref ecore_config_load to allow a user to * override the default search path. * - * @param path The given + * @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. @@ -420,8 +422,8 @@ ecore_config_theme_search_path_append(const char *path) loc = strstr(search_path, path); len = strlen(path); search_len = strlen(search_path); - - if (loc == NULL || (loc != search_path && *(loc - 1) != '|') || + + 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 + | */ @@ -475,9 +477,9 @@ ecore_config_theme_with_path_from_name_get(char *name) file = malloc(strlen(search_path_tmp) + strlen(name) + 6); /* 6 = / + .edj + \0 */ - snprintf(file, strlen(search_path_tmp) + strlen(name) + 6, + snprintf(file, strlen(search_path_tmp) + strlen(name) + 6, "%s/%s.edj", search_path_tmp, name); - + if (stat(file, &st) == 0) { free(search_path); @@ -525,9 +527,9 @@ ecore_config_args_display(void) _Ecore_Config_Arg_Callback *callbacks; if (__ecore_config_app_description) - printf("%s\n\n", __ecore_config_app_description); - printf("Supported Options:\n"); - printf(" -h, --help\t Print this text\n"); + 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; @@ -539,7 +541,7 @@ ecore_config_args_display(void) props = props->next; continue; } - printf(" %c%c%c --%s\t%s %s\n", props->short_opt ? '-' : ' ', + 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, @@ -552,7 +554,7 @@ ecore_config_args_display(void) callbacks = _ecore_config_arg_callbacks; while (callbacks) { - printf(" %c%c%c --%s\t%s %s\n", callbacks->short_opt ? '-' : ' ', + 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 : "", @@ -571,16 +573,16 @@ ecore_config_parse_set(Ecore_Config_Prop * prop, char *arg, char *opt, if (!arg) { if (opt) - printf("Missing expected argument for option --%s\n", opt); + ERR("Missing expected argument for option --%s", opt); else - printf("Missing expected argument for option -%c\n", opt2); + 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; } @@ -646,7 +648,7 @@ ecore_config_args_parse(void) if (*arg != '-') { - printf("Unexpected attribute \"%s\"\n", arg); + ERR("Unexpected attribute \"%s\"", arg); nextarg++; continue; } @@ -687,7 +689,7 @@ ecore_config_args_parse(void) callback = _ecore_config_arg_callbacks; while (callback) { - if ((callback->long_opt && + if ((callback->long_opt && !strcmp(long_opt, callback->long_opt))) { found = 1; @@ -695,11 +697,11 @@ ecore_config_args_parse(void) { callback->func(NULL, callback->data); } - else + else { if (!argv[++nextarg]) { - printf("Missing expected argument for option --%s\n", long_opt); + ERR("Missing expected argument for option --%s", long_opt); return ECORE_CONFIG_PARSE_EXIT; } callback->func(argv[nextarg], callback->data); @@ -711,8 +713,8 @@ ecore_config_args_parse(void) } if (!found) { - printf("Unrecognised option \"%s\"\n", long_opt); - printf("Try using -h or --help for more information.\n\n"); + ERR("Unrecognised option \"%s\"", long_opt); + ERR("Try using -h or --help for more information.\n"); return ECORE_CONFIG_PARSE_EXIT; } } @@ -762,7 +764,7 @@ ecore_config_args_parse(void) { if (!argv[++nextarg]) { - printf("Missing expected argument for option -%c\n", short_opt); + ERR("Missing expected argument for option -%c", short_opt); return ECORE_CONFIG_PARSE_EXIT; } callback->func(argv[nextarg], callback->data); @@ -774,9 +776,8 @@ ecore_config_args_parse(void) } if (!found) { - printf("Unrecognised option '%c'\n", short_opt); - printf - ("Try using -h or --help for more information.\n\n"); + ERR("Unrecognised option '%c'", short_opt); + ERR("Try using -h or --help for more information.\n"); return ECORE_CONFIG_PARSE_EXIT; } } diff --git a/src/lib/ecore_config/ecore_config_ipc_ecore.c b/src/lib/ecore_config/ecore_config_ipc_ecore.c index 44fa9d0..b1622f3 100644 --- a/src/lib/ecore_config/ecore_config_ipc_ecore.c +++ b/src/lib/ecore_config/ecore_config_ipc_ecore.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + /* by Azundris, with thanks to Corey Donohoe */ #include #include @@ -10,15 +14,14 @@ #include #include +#include "ecore_private.h" #include -#include "ecore_private.h" #include "ecore_config_ipc.h" #include "ecore_config_util.h" #include "ecore_config_private.h" #include "Ecore_Config.h" -#include "config.h" /*****************************************************************************/ @@ -42,7 +45,7 @@ _ecore_config_ipc_ecore_string_get(char **m, char **r) *r = q; q += l; *m = q; - E(1, "IPC/eCore: got string-%d \"%s\"\n", l, *r); + WRN("IPC/eCore: got string-%d \"%s\"", l, *r); return ECORE_CONFIG_ERR_SUCC; } @@ -54,7 +57,7 @@ _ecore_config_ipc_global_prop_list(Ecore_Config_Server * srv __UNUSED__, long se int key_count, x; estring *s; int f; - char buf[PATH_MAX], *p; + char buf[PATH_MAX], *p; // char *data; UNUSED Ecore_Config_Type type; @@ -118,7 +121,7 @@ _ecore_config_ipc_global_prop_list(Ecore_Config_Server * srv __UNUSED__, long se } free(keys); } - + return estring_disown(s); } @@ -132,7 +135,7 @@ _ecore_config_ipc_ecore_send(Ecore_Ipc_Event_Client_Data * e, int code, int len = reply ? strlen(reply) + 1 : 0; our_ref++; - E(1, "IPC/eCore: replying [0,0] %d IRT %d => %d {\"%s\":%d}\n", 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); @@ -151,10 +154,9 @@ _ecore_config_ipc_ecore_handle_request(Ecore_Ipc_Server * server, srv = _ecore_config_server_convert(server); serial = e->minor; - ret = ECORE_CONFIG_ERR_FAIL; r = NULL; m = (char *)e->data; - E(1, "IPC/eCore: client sent: [%d,%d] #%d (%d) @ %p\n", e->major, e->minor, + INF("IPC/eCore: client sent: [%d,%d] #%d (%d) @ %p", e->major, e->minor, e->ref, e->size, server); switch (e->major) @@ -229,7 +231,7 @@ _ecore_config_ipc_ecore_handle_request(Ecore_Ipc_Server * server, /*****************************************************************************/ -static int +static Eina_Bool _ecore_config_ipc_client_add(void *data, int type __UNUSED__, void *event) { Ecore_Ipc_Server **server; @@ -239,13 +241,13 @@ _ecore_config_ipc_client_add(void *data, int type __UNUSED__, void *event) e = (Ecore_Ipc_Event_Client_Data *) event; if (*server != ecore_ipc_client_server_get(e->client)) - return 1; + return EINA_TRUE; - E(1, "IPC/eCore: Client connected. @ %p\n", server); - return 1; + INF("IPC/eCore: Client connected. @ %p", server); + return EINA_TRUE; } -static int +static Eina_Bool _ecore_config_ipc_client_del(void *data, int type __UNUSED__, void *event) { Ecore_Ipc_Server **server; @@ -255,13 +257,13 @@ _ecore_config_ipc_client_del(void *data, int type __UNUSED__, void *event) e = (Ecore_Ipc_Event_Client_Data *) event; if (*server != ecore_ipc_client_server_get(e->client)) - return 1; + return EINA_TRUE; - E(1, "IPC/eCore: Client disconnected. @ %p\n", server); - return 1; + INF("IPC/eCore: Client disconnected. @ %p", server); + return EINA_TRUE; } -static int +static Eina_Bool _ecore_config_ipc_client_sent(void *data, int type __UNUSED__, void *event) { Ecore_Ipc_Server **server; @@ -271,10 +273,10 @@ _ecore_config_ipc_client_sent(void *data, int type __UNUSED__, void *event) e = (Ecore_Ipc_Event_Client_Data *) event; if (*server != ecore_ipc_client_server_get(e->client)) - return 1; + return EINA_TRUE; _ecore_config_ipc_ecore_handle_request(*server, e); - return 1; + return EINA_TRUE; } /*****************************************************************************/ @@ -311,7 +313,7 @@ _ecore_config_ipc_ecore_init(const char *pipe_name, void **data) if (!stat(socket, &st)) { - E(0, "IPC/eCore: pipe \"%s\" already exists!?\n", socket); + 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++; @@ -330,9 +332,9 @@ _ecore_config_ipc_ecore_init(const char *pipe_name, void **data) ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA, _ecore_config_ipc_client_sent, server); - if (server) + if (*server) { - E(1, "IPC/eCore: Server is listening on %s.\n", pipe_name); + INF("IPC/eCore: Server is listening on %s.", pipe_name); } return ECORE_CONFIG_ERR_SUCC; @@ -357,6 +359,7 @@ _ecore_config_ipc_ecore_exit(void **data) } ecore_ipc_shutdown(); + ecore_shutdown(); return ret; } diff --git a/src/lib/ecore_config/ecore_config_ipc_main.c b/src/lib/ecore_config/ecore_config_ipc_main.c index 5d6a18a..35bd783 100644 --- a/src/lib/ecore_config/ecore_config_ipc_main.c +++ b/src/lib/ecore_config/ecore_config_ipc_main.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + /* ############## bad */ #define HAVE_EVAS2 @@ -15,7 +19,6 @@ #include "ecore_config_util.h" #include "ecore_config_ipc.h" -#include "config.h" #include "ecore_config_private.h" static Ecore_Config_Server *__ecore_config_servers; @@ -86,12 +89,9 @@ _ecore_config_ipc_prop_desc(Ecore_Config_Server * srv, const long serial, const char *key) { #ifdef HAVE_EVAS2 - Ecore_Config_Bundle *theme; Ecore_Config_Prop *e; - theme = ecore_config_bundle_by_serial_get(srv, serial); e = ecore_config_get(key); - if (e) { estring *s = estring_new(512); @@ -111,11 +111,8 @@ _ecore_config_ipc_prop_get(Ecore_Config_Server * srv, const long serial, { #ifdef HAVE_EVAS2 char *ret; - Ecore_Config_Bundle *theme; - ret = NULL; - theme = ecore_config_bundle_by_serial_get(srv, serial); - if ((ret = ecore_config_as_string_get( /*theme, */ key))) + if ((ret = ecore_config_as_string_get(key))) return ret; #endif return strdup(""); @@ -131,8 +128,8 @@ _ecore_config_ipc_prop_set(Ecore_Config_Server * srv, const long serial, theme = ecore_config_bundle_by_serial_get(srv, serial); ret = ecore_config_set(key, (char *)val); - E(1, "ipc.prop.set(%s->%s,\"%s\") => %d\n", theme ? theme->identifier : "", - key, val, ret); + ERR("ipc.prop.set(%s->%s,\"%s\") => %d\n", theme ? theme->identifier : "", + key, val, ret); return ret; #else return ECORE_CONFIG_ERR_NOTSUPP; @@ -208,7 +205,7 @@ _ecore_config_ipc_bundle_label_find(Ecore_Config_Server * srv, return ns ? ecore_config_bundle_serial_get(ns) : -1; } -static int +static Eina_Bool _ecore_config_ipc_poll(void *data __UNUSED__) { Ecore_Config_Server *s; @@ -220,7 +217,7 @@ _ecore_config_ipc_poll(void *data __UNUSED__) s = s->next; } - return 1; + return EINA_TRUE; } int @@ -254,15 +251,14 @@ _ecore_config_ipc_init(const char *pipe_name) ret_srv = NULL; list = NULL; - list = malloc(sizeof(Ecore_Config_Server)); - memset(list, 0, sizeof(Ecore_Config_Server)); + list = calloc(1, sizeof(Ecore_Config_Server)); if ((ret = _ecore_config_ipc_ecore_init(pipe_name, &list->server)) != ECORE_CONFIG_ERR_SUCC) { - E(2, "_ecore_config_ipc_init: failed to register %s, code %d\n", + ERR("_ecore_config_ipc_init: failed to register %s, code %d", pipe_name, ret); } - E(2, "_ecore_config_ipc_init: registered \"%s\"...\n", pipe_name); + ERR("_ecore_config_ipc_init: registered \"%s\"...", pipe_name); list->name = strdup(pipe_name); list->next = __ecore_config_servers; @@ -273,7 +269,7 @@ _ecore_config_ipc_init(const char *pipe_name) 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 index 3beee54..b97f695 100644 --- a/src/lib/ecore_config/ecore_config_private.h +++ b/src/lib/ecore_config/ecore_config_private.h @@ -1,15 +1,40 @@ #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; -#ifdef __sgi -# define D -# define E -#else -# define D(fmt,args...) do { if(DEBUG>=0) fprintf(stderr,fmt,## args); } while(0); -# define E(lvl,args...) do { if(DEBUG>=(lvl)) fprintf(stderr,## args); } while(0) -#endif + typedef struct _Ecore_Config_DB_File Ecore_Config_DB_File; @@ -39,6 +64,7 @@ int _ecore_config_ipc_ecore_init(const char *pipe_name, void * 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 index 104dd18..d059645 100644 --- a/src/lib/ecore_config/ecore_config_storage.c +++ b/src/lib/ecore_config/ecore_config_storage.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + #include #include #include @@ -76,10 +80,10 @@ ecore_config_file_load(const char *file) db = _ecore_config_db_open_read(file); if (!db) { - E(0, "Cannot open database from file %s!\n", file); + ERR("Cannot open database from file %s!", file); return ECORE_CONFIG_ERR_NODATA; } - key_count = 0; + key_count = 0; keys = _ecore_config_db_keys_get(db, &key_count); if (keys) { @@ -146,7 +150,7 @@ ecore_config_file_save(const char *file) db = _ecore_config_db_open_write(file); if (!db) { - E(0, "Cannot open database from file %s!\n", file); + ERR("Cannot open database from file %s!", file); return ECORE_CONFIG_ERR_FAIL; } diff --git a/src/lib/ecore_config/ecore_config_util.c b/src/lib/ecore_config/ecore_config_util.c index 6ee17c3..6156936 100644 --- a/src/lib/ecore_config/ecore_config_util.c +++ b/src/lib/ecore_config/ecore_config_util.c @@ -1,11 +1,17 @@ +#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" diff --git a/src/lib/ecore_directfb/Ecore_DirectFB.h b/src/lib/ecore_directfb/Ecore_DirectFB.h index 7f9e898..3b94816 100644 --- a/src/lib/ecore_directfb/Ecore_DirectFB.h +++ b/src/lib/ecore_directfb/Ecore_DirectFB.h @@ -1,34 +1,27 @@ #ifndef _ECORE_DIRECTFB_H #define _ECORE_DIRECTFB_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 +#include -#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 +#endif /* ifdef __cplusplus */ EAPI extern int ECORE_DIRECTFB_EVENT_POSITION; EAPI extern int ECORE_DIRECTFB_EVENT_SIZE; @@ -45,148 +38,144 @@ 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 -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; - +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 */ + * 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; - + DFBWindowID id; + IDirectFBWindow *window; + IDirectFBSurface *surface; + Ecore_DirectFB_Cursor *cursor; }; struct _Ecore_DirectFB_Cursor { - IDirectFBSurface *surface; - int hot_x; - int hot_y; - + 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; + 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; + 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; + 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 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; + 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; + 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; + 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; + int direction; + int z; + int modifiers; + unsigned int time; + DFBWindowID win; }; struct _Ecore_DirectFB_Event_Got_Focus { - unsigned int time; - DFBWindowID win; + unsigned int time; + DFBWindowID win; }; struct _Ecore_DirectFB_Event_Lost_Focus { - unsigned int time; - DFBWindowID win; + 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_del(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, int set); -EAPI void ecore_directfb_window_fullscreen_set(Ecore_DirectFB_Window *window, int 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, int show); - +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 +#endif /* ifdef __cplusplus */ -#endif +#endif /* ifndef _ECORE_DIRECTFB_H */ diff --git a/src/lib/ecore_directfb/Makefile.am b/src/lib/ecore_directfb/Makefile.am index a2f693b..8142d33 100644 --- a/src/lib/ecore_directfb/Makefile.am +++ b/src/lib/ecore_directfb/Makefile.am @@ -3,13 +3,11 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_builddir)/src/lib/ecore \ -@DIRECTFB_CFLAGS@ - -if BUILD_ECORE_DIRECTFB +@DIRECTFB_CFLAGS@ @EINA_CFLAGS@ lib_LTLIBRARIES = libecore_directfb.la -include_HEADERS = \ -Ecore_DirectFB.h +includes_HEADERS = Ecore_DirectFB.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_directfb_la_SOURCES = \ ecore_directfb.c \ @@ -18,15 +16,14 @@ ecore_directfb_private.h libecore_directfb_la_LIBADD = \ $(top_builddir)/src/lib/ecore/libecore.la \ -@DIRECTFB_LIBS@ +@DIRECTFB_LIBS@ \ +@EINA_LIBS@ -libecore_directfb_la_LDFLAGS = -version-info @version_info@ +libecore_directfb_la_LDFLAGS = -version-info @version_info@ @release_info@ libecore_directfb_la_DEPENDENCIES = \ $(top_builddir)/src/lib/ecore/libecore.la -endif - EXTRA_DIST = \ Ecore_DirectFB.h \ ecore_directfb.c \ diff --git a/src/lib/ecore_directfb/ecore_directfb.c b/src/lib/ecore_directfb/ecore_directfb.c index ce4bb76..7c56b5d 100644 --- a/src/lib/ecore_directfb/ecore_directfb.c +++ b/src/lib/ecore_directfb/ecore_directfb.c @@ -1,8 +1,15 @@ -#include "ecore_private.h" +#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 */ /******************/ @@ -10,10 +17,10 @@ /* 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_key_symbols_count = sizeof(_ecore_directfb_key_symbols)/sizeof(Ecore_DirectFB_Key_Symbols); static int _ecore_directfb_init_count = 0; static int _window_event_fd = 0; @@ -38,20 +45,17 @@ 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 Ecore_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; // usefull for DFBCHECK +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 */ @@ -60,15 +64,21 @@ static DFBResult _err; // usefull for DFBCHECK /* free ecore directfb events functions */ /****************************************/ -static void +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); + if(e->name) + free(e->name); + + if (e->string) + free(e->string); + + if (e->key_compose) + free(e->key_compose); + free(e); } @@ -76,671 +86,672 @@ 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); -} + e = ev; + if(e->name) + free(e->name); -/* helpers */ -/***********/ -int -_ecore_directfb_hash_compare(void *key1, void *key2) -{ - if(*(unsigned int*)key1 == *(unsigned int*)key2) - return 0; - else - return 1; + if (e->string) + free(e->string); -} + if (e->key_compose) + free(e->key_compose); -unsigned int _ecore_directfb_hash_create(void *key) -{ - return *(unsigned int*)key % ecore_prime_table[_ecore_directfb_key_symbols_hash->size]; + 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); + 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 = ecore_hash_get(_ecore_directfb_key_symbols_hash, &key_symbol); - - if(!k) - { - printf("error en el numero, %0X\n", 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 = ecore_hash_get(_ecore_directfb_key_symbols_hash, &key_symbol); - - if(!k) - { - printf("error en el numero, %0X\n", 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); + 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 = ecore_hash_get(_ecore_directfb_key_symbols_hash, &key_symbol); - - - if(!k) - { - printf("error en el numero, %0X\n", 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 = ecore_hash_get(_ecore_directfb_key_symbols_hash, &key_symbol); - - if(!k) - { - printf("error en el numero, %0X\n", 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); - + 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); - + 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); - + 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)); + 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); + 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)); + 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); + 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); + 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)); + 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); + 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)); + 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); + 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 int +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 1; - if (v < 1) return 1; - - /* 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 1; + 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 int + +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 1; - if (v < 1) return 1; - - if(evt.window.type & DWET_POSITION) - printf("position\n"); - if(evt.window.type & DWET_SIZE) - printf("size\n"); - if(evt.window.type & DWET_CLOSE) - printf("close\n"); - if(evt.window.type & DWET_DESTROYED) - printf("destroyed\n"); - 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 1; + 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; + 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; + 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_del(Ecore_DirectFB_Window *ecore_window) +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); + 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)); + 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)); + DFBCHECK(ecore_window->window->Resize(ecore_window->window, w, h)); } -EAPI void +EAPI void ecore_directfb_window_focus(Ecore_DirectFB_Window *ecore_window) -{ - DFBCHECK(ecore_window->window->RequestFocus(ecore_window->window)); +{ + DFBCHECK(ecore_window->window->RequestFocus(ecore_window->window)); } -EAPI void +EAPI void ecore_directfb_window_hide(Ecore_DirectFB_Window *ecore_window) { - DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window,0)); - + 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)); + DFBCHECK(ecore_window->window->SetOpacity(ecore_window->window, 0xFF)); } EAPI void -ecore_directfb_window_shaped_set(Ecore_DirectFB_Window *ecore_window, int set) +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)); - } + 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, int show) +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)); - } - - } + 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)); - - } - + 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, int on) +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 - { - DFBCHECK(_input_event->Release(_input_event)); - DFBCHECK(_layer->SetCooperativeLevel(_layer,DLSCL_SHARED)); - DFBCHECK(ecore_window->window->GetSurface(ecore_window->window, &ecore_window->surface)); - ecore_main_fd_handler_del(_input_event_fd_handler_handle); - _ecore_directfb_fullscreen_window_id = 0; - } - + // 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; + DFBCHECK(ecore_window->surface->GetSize(ecore_window->surface,w,h)); + return; } EAPI int -ecore_directfb_init(const char *name) +ecore_directfb_init(const char *name __UNUSED__) { - int i = 0; - - _ecore_directfb_init_count++; - if (_ecore_directfb_init_count > 1) 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 = ecore_hash_new(_ecore_directfb_hash_create,_ecore_directfb_hash_compare); - 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; - ecore_hash_set(_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; + 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) { - int i; - - _ecore_directfb_init_count--; - if (_ecore_directfb_init_count > 0) return _ecore_directfb_init_count; - if (_ecore_directfb_init_count < 0) - { - _ecore_directfb_init_count = 0; - return 0; - } - ecore_main_fd_handler_del(_window_event_fd_handler_handle); - /* free the key symbol names hash */ - for(i=0; i<_ecore_directfb_key_symbols_count; i++) - { - struct keymap *k; - k = ecore_hash_get(_ecore_directfb_key_symbols_hash, &_ecore_directfb_key_symbols[i].id); - ecore_hash_remove(_ecore_directfb_key_symbols_hash, &_ecore_directfb_key_symbols[i].id); - free(k); - } - - 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)); - - return 1; + 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 index e24d715..19cca46 100644 --- a/src/lib/ecore_directfb/ecore_directfb_keys.h +++ b/src/lib/ecore_directfb/ecore_directfb_keys.h @@ -1,181 +1,184 @@ -typedef struct _Ecore_DirectFB_Key_Symbols Ecore_DirectFB_Key_Symbols; +typedef struct _Ecore_DirectFB_Key_Symbols Ecore_DirectFB_Key_Symbols; struct _Ecore_DirectFB_Key_Symbols { - char *string; - char *name; - unsigned int id; -} _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} + 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 index fc9ef5e..ed34587 100644 --- a/src/lib/ecore_directfb/ecore_directfb_private.h +++ b/src/lib/ecore_directfb/ecore_directfb_private.h @@ -1,15 +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) { \ - fprintf( stderr, "%s <%d>:\n\t", __FILE__, __LINE__ ); \ - DirectFBErrorFatal( #x, _err ); \ - } \ - } +#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; + 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 index e8125b0..8a93180 100644 --- a/src/lib/ecore_evas/Ecore_Evas.h +++ b/src/lib/ecore_evas/Ecore_Evas.h @@ -1,10 +1,10 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef _ECORE_EVAS_H #define _ECORE_EVAS_H +#include +#include +#include + #ifdef EAPI # undef EAPI #endif @@ -34,6 +34,14 @@ /** * @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: @@ -48,12 +56,36 @@ * - dfb back-end ??? (dfb's threads make this REALLY HARD) */ -#include - #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. */ @@ -63,26 +95,39 @@ extern "C" { #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_X11, + 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_SDL, + 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 @@ -92,6 +137,14 @@ typedef enum _Ecore_Evas_Avoid_Damage_Type 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; @@ -103,193 +156,2118 @@ typedef struct _Ecore_DirectFB_Window Ecore_DirectFB_Window; #endif #ifndef __ECORE_WIN32_H__ -typedef void Ecore_Win32_Window; +typedef struct _Ecore_Win32_Window Ecore_Win32_Window; #endif #ifndef __ECORE_WINCE_H__ -typedef void Ecore_WinCE_Window; +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); -/* 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(Ecore_Evas *ee); -EAPI Ecore_X_Window ecore_evas_software_x11_subwindow_get(Ecore_Evas *ee); -EAPI void ecore_evas_software_x11_direct_resize_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_software_x11_direct_resize_get(Ecore_Evas *ee); -EAPI void ecore_evas_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); - -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_X_Window ecore_evas_gl_x11_window_get(Ecore_Evas *ee); -EAPI Ecore_X_Window ecore_evas_gl_x11_subwindow_get(Ecore_Evas *ee); -EAPI void ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_gl_x11_direct_resize_get(Ecore_Evas *ee); -EAPI void ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win); - -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(Ecore_Evas *ee); -EAPI Ecore_X_Window ecore_evas_xrender_x11_subwindow_get(Ecore_Evas *ee); -EAPI void ecore_evas_xrender_x11_direct_resize_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_xrender_x11_direct_resize_get(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_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(Ecore_Evas *ee); -EAPI Ecore_X_Window ecore_evas_software_x11_16_subwindow_get(Ecore_Evas *ee); -EAPI void ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_software_x11_16_direct_resize_get(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(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(Ecore_Evas *ee); - -EAPI Ecore_Evas *ecore_evas_buffer_new(int w, int h); -EAPI const int *ecore_evas_buffer_pixels_get(Ecore_Evas *ee); - -EAPI Evas_Object *ecore_evas_object_image_new(Ecore_Evas *ee_target); - -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_ddraw_16_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(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_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 void ecore_evas_app_comp_sync_set(Eina_Bool do_sync); +EAPI Eina_Bool ecore_evas_app_comp_sync_get(void); -EAPI Ecore_WinCE_Window *ecore_evas_software_wince_window_get(Ecore_Evas *ee); +/** + * @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); -/* generic manipulation calls */ -EAPI Ecore_Evas *ecore_evas_ecore_evas_get(Evas *e); -EAPI void ecore_evas_free(Ecore_Evas *ee); -EAPI void *ecore_evas_data_get(Ecore_Evas *ee, const char *key); -EAPI void ecore_evas_data_set(Ecore_Evas *ee, const char *key, const void *data); -EAPI void ecore_evas_callback_resize_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_move_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_show_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_hide_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_delete_request_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_destroy_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_focus_in_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_focus_out_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_sticky_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_unsticky_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_pre_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI void ecore_evas_callback_post_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); -EAPI Evas *ecore_evas_get(Ecore_Evas *ee); -EAPI void ecore_evas_move(Ecore_Evas *ee, int x, int y); -EAPI void ecore_evas_managed_move(Ecore_Evas *ee, int x, int y); -EAPI void ecore_evas_resize(Ecore_Evas *ee, int w, int h); -EAPI void ecore_evas_move_resize(Ecore_Evas *ee, int x, int y, int w, int h); -EAPI void ecore_evas_geometry_get(Ecore_Evas *ee, int *x, int *y, int *w, int *h); -EAPI void ecore_evas_rotation_set(Ecore_Evas *ee, int rot); -EAPI int ecore_evas_rotation_get(Ecore_Evas *ee); -EAPI void ecore_evas_shaped_set(Ecore_Evas *ee, int shaped); -EAPI int ecore_evas_shaped_get(Ecore_Evas *ee); -EAPI void ecore_evas_alpha_set(Ecore_Evas *ee, int alpha); -EAPI int ecore_evas_alpha_get(Ecore_Evas *ee); -EAPI void ecore_evas_show(Ecore_Evas *ee); -EAPI void ecore_evas_hide(Ecore_Evas *ee); -EAPI int ecore_evas_visibility_get(Ecore_Evas *ee); -EAPI void ecore_evas_raise(Ecore_Evas *ee); -EAPI void ecore_evas_lower(Ecore_Evas *ee); -EAPI void ecore_evas_activate(Ecore_Evas *ee); -EAPI void ecore_evas_title_set(Ecore_Evas *ee, const char *t); -EAPI const char *ecore_evas_title_get(Ecore_Evas *ee); -EAPI void ecore_evas_name_class_set(Ecore_Evas *ee, const char *n, const char *c); -EAPI void ecore_evas_name_class_get(Ecore_Evas *ee, const char **n, const char **c); -EAPI void ecore_evas_size_min_set(Ecore_Evas *ee, int w, int h); -EAPI void ecore_evas_size_min_get(Ecore_Evas *ee, int *w, int *h); -EAPI void ecore_evas_size_max_set(Ecore_Evas *ee, int w, int h); -EAPI void ecore_evas_size_max_get(Ecore_Evas *ee, int *w, int *h); -EAPI void ecore_evas_size_base_set(Ecore_Evas *ee, int w, int h); -EAPI void ecore_evas_size_base_get(Ecore_Evas *ee, int *w, int *h); +/** + * @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_SWAP_MODE 3 +#define ECORE_EVAS_GL_X11_OPT_LAST 4 + +#define ECORE_EVAS_GL_X11_SWAP_MODE_AUTO 0 +#define ECORE_EVAS_GL_X11_SWAP_MODE_FULL 1 +#define ECORE_EVAS_GL_X11_SWAP_MODE_COPY 2 +#define ECORE_EVAS_GL_X11_SWAP_MODE_DOUBLE 3 +#define ECORE_EVAS_GL_X11_SWAP_MODE_TRIPLE 4 + +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_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); -EAPI void ecore_evas_size_step_get(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); -EAPI void ecore_evas_cursor_get(Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y); -EAPI void ecore_evas_layer_set(Ecore_Evas *ee, int layer); -EAPI int ecore_evas_layer_get(Ecore_Evas *ee); -EAPI void ecore_evas_focus_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_focus_get(Ecore_Evas *ee); -EAPI void ecore_evas_iconified_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_iconified_get(Ecore_Evas *ee); -EAPI void ecore_evas_borderless_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_borderless_get(Ecore_Evas *ee); -EAPI void ecore_evas_override_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_override_get(Ecore_Evas *ee); -EAPI void ecore_evas_maximized_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_maximized_get(Ecore_Evas *ee); -EAPI void ecore_evas_fullscreen_set(Ecore_Evas *ee, int on); -EAPI int ecore_evas_fullscreen_get(Ecore_Evas *ee); + +/** + * 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); -EAPI Ecore_Evas_Avoid_Damage_Type ecore_evas_avoid_damage_get(Ecore_Evas *ee); -EAPI void ecore_evas_withdrawn_set(Ecore_Evas *ee, int withdrawn); -EAPI int ecore_evas_withdrawn_get(Ecore_Evas *ee); -EAPI void ecore_evas_sticky_set(Ecore_Evas *ee, int sticky); -EAPI int ecore_evas_sticky_get(Ecore_Evas *ee); -EAPI void ecore_evas_ignore_events_set(Ecore_Evas *ee, int ignore); -EAPI int ecore_evas_ignore_events_get(Ecore_Evas *ee); -EAPI void *ecore_evas_window_get(Ecore_Evas *ee); + +/** + * 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 } diff --git a/src/lib/ecore_evas/Makefile.am b/src/lib/ecore_evas/Makefile.am index 0a37748..db77449 100644 --- a/src/lib/ecore_evas/Makefile.am +++ b/src/lib/ecore_evas/Makefile.am @@ -1,8 +1,8 @@ MAINTAINERCLEANFILES = Makefile.in if BUILD_ECORE_X -ECORE_X_INC = -I$(top_srcdir)/src/lib/ecore_x -ECORE_X_LIB = $(top_builddir)/src/lib/ecore_x/libecore_x.la +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 = @@ -35,9 +35,19 @@ 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 @@ -48,37 +58,84 @@ 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@ \ -@XCB_CFLAGS@ +@EINA_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@WAYLAND_EGL_CFLAGS@ AM_CFLAGS = @WIN32_CFLAGS@ -if BUILD_ECORE_EVAS - lib_LTLIBRARIES = libecore_evas.la -include_HEADERS = \ -Ecore_Evas.h +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_wince.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 + +if BUILD_ECORE_WAYLAND +libecore_evas_la_SOURCES += \ +ecore_evas_wayland_common.c +endif libecore_evas_la_LIBADD = \ $(ECORE_X_LIB) \ @@ -86,25 +143,23 @@ $(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@ \ -@XCB_LIBS@ \ -@SDL_LIBS@ \ -@EVIL_LIBS@ - -libecore_evas_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +@EINA_LIBS@ \ +@EVIL_LIBS@ \ +@EFL_SHM_OPEN_LIBS@ \ +@WAYLAND_EGL_LIBS@ -libecore_evas_la_DEPENDENCIES = \ -$(ECORE_X_LIB) \ -$(ECORE_FB_LIB) \ -$(ECORE_DIRECTFB_LIB) \ -$(ECORE_WIN32_LIB) \ -$(ECORE_SDL_LIB) \ -$(ECORE_WINCE_LIB) \ -$(top_builddir)/src/lib/ecore/libecore.la - -endif +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 index c49b916..541c51b 100644 --- a/src/lib/ecore_evas/ecore_evas.c +++ b/src/lib/ecore_evas/ecore_evas.c @@ -1,19 +1,77 @@ - #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 renginering engine target has support + * Query if a particular rendering engine target has support * @param engine The engine to check support for - * @return 1 if the particualr engine is supported, 0 if it is not + * @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. @@ -24,1307 +82,1654 @@ ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine) switch (engine) { case ECORE_EVAS_ENGINE_SOFTWARE_BUFFER: -#ifdef BUILD_ECORE_EVAS_BUFFER - return 1; +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif - case ECORE_EVAS_ENGINE_SOFTWARE_X11: -#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 - return 1; + case ECORE_EVAS_ENGINE_SOFTWARE_XLIB: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_XLIB + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_XRENDER_X11: -#ifdef BUILD_ECORE_EVAS_XRENDER_X11 - return 1; -#else - return 0; -#endif + return EINA_FALSE; case ECORE_EVAS_ENGINE_OPENGL_X11: #ifdef BUILD_ECORE_EVAS_OPENGL_X11 - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_XCB: #ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_XRENDER_XCB: -#ifdef BUILD_ECORE_EVAS_XRENDER_XCB - return 1; + return EINA_FALSE; + case ECORE_EVAS_ENGINE_SOFTWARE_GDI: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_GDI + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_DDRAW: #ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_DIRECT3D: #ifdef BUILD_ECORE_EVAS_DIRECT3D - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_OPENGL_GLEW: #ifdef BUILD_ECORE_EVAS_OPENGL_GLEW - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif - case ECORE_EVAS_ENGINE_SDL: -#ifdef BUILD_ECORE_EVAS_SDL - return 1; + case ECORE_EVAS_ENGINE_SOFTWARE_SDL: +#ifdef BUILD_ECORE_EVAS_SOFTWARE_SDL + return EINA_TRUE; #else - return 0; + 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 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_FB: #ifdef BUILD_ECORE_EVAS_FB - return 1; + 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 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_16_X11: #ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_16_DDRAW: #ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DDRAW - return 1; + return EINA_TRUE; #else - return 0; + return EINA_FALSE; #endif case ECORE_EVAS_ENGINE_SOFTWARE_16_WINCE: #ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return 1; + return EINA_TRUE; #else - return 0; + 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 0; - break; + return EINA_FALSE; }; - return 0; } -/** - * Init the Evas system. - * @return greater than 0 on success, 0 on failure - * - * Set up the Evas wrapper system. - */ +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) { - if (_ecore_evas_init_count == 0) - evas_init (); - return ++_ecore_evas_init_count; + 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; } -/** - * Shut down the Evas system. - * @return 0 if ecore evas is fully shut down, or > 0 if it still needs to be shut down - * - * This closes the Evas system down. - */ EAPI int ecore_evas_shutdown(void) { - _ecore_evas_init_count--; - if (_ecore_evas_init_count == 0) - { + 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()); + while (_ecore_evas_x_shutdown()); #endif #ifdef BUILD_ECORE_EVAS_WIN32 - while (_ecore_evas_win32_shutdown()); + while (_ecore_evas_win32_shutdown()); #endif #ifdef BUILD_ECORE_EVAS_FB - while (_ecore_evas_fb_shutdown()); + while (_ecore_evas_fb_shutdown()); +#endif +#ifdef BUILD_ECORE_EVAS_EWS + while (_ecore_evas_ews_shutdown()); #endif -#ifdef BUILD_ECORE_EVAS_BUFFER - while (_ecore_evas_buffer_shutdown()); +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + while (_ecore_evas_buffer_shutdown()); #endif #ifdef BUILD_ECORE_EVAS_DIRECTFB - while (_ecore_evas_directfb_shutdown()); + while (_ecore_evas_directfb_shutdown()); #endif #ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - while (_ecore_evas_wince_shutdown()); + while (_ecore_evas_wince_shutdown()); #endif - evas_shutdown(); - } - if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; + + 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; } -/** - * 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 - */ +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_ecore_evas_get(Evas *e) +ecore_evas_new(const char *engine_name, int x, int y, int w, int h, const char *extra_options) { - return evas_data_attach_get(e); + 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; } -/** - * 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) { if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_free"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_free"); + return; } _ecore_evas_free(ee); return; } -/** - * 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 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(Ecore_Evas *ee, const char *key) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_data_get"); + return NULL; } if (!key) return NULL; + if (!ee->data) return NULL; - return evas_hash_find(ee->data, key); + return eina_hash_find(ee->data, key); } -/** - * Store user data in an Ecore_Evas structure. - * - * @param eeThe Ecore_Evas to store the user data in. - * @param keyA unique string to associate the user data against. Cannot - * be NULL. - * @param dataA 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_free - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_data_set"); + return; } if (!key) return; - ee->data = evas_hash_del(ee->data, key, NULL); + if (ee->data) + eina_hash_del(ee->data, key, NULL); if (data) - ee->data = evas_hash_add(ee->data, key, 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;} -/** - * 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. - */ EAPI void -ecore_evas_callback_resize_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_move_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_show_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_hide_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_delete_request_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_destroy_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_focus_in_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_focus_out_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_sticky_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_unsticky_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_mouse_in_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_mouse_out_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * Set a callback for Ecore_Evas mouse 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. - */ EAPI void -ecore_evas_callback_pre_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_callback_post_render_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) +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; + 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; } -/** - * 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 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(Ecore_Evas *ee) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_get"); + return NULL; } return ee->evas; } -/** - * 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) - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_move"); + return; } + if (ee->prop.fullscreen) return; IFC(ee, fn_move) (ee, x, y); IFE; } -/** - * 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) { if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_move"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_move"); + return; } IFC(ee, fn_managed_move) (ee, x, y); IFE; } -/** - * 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 - */ 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; + 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; + IFC(ee, fn_resize) (ee, h, w); + IFE; } else { - IFC(ee, fn_resize) (ee, w, h); - IFE; + IFC(ee, fn_resize) (ee, w, h); + IFE; } } -/** - * Resize 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 - * @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. - * - */ 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; + 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; + IFC(ee, fn_move_resize) (ee, x, y, h, w); + IFE; } else { - IFC(ee, fn_move_resize) (ee, x, y, w, h); - IFE; + IFC(ee, fn_move_resize) (ee, x, y, w, h); + IFE; } } -/** - * 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. - * - * @code - * int x, y, w, h; - * ecore_evas_geometry_get(ee, &x, &y, &w, &h); - * @endcode - * - */ EAPI void -ecore_evas_geometry_get(Ecore_Evas *ee, int *x, int *y, int *w, int *h) +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; + 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; + 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; + 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; } } -/** - * 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. - */ 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; + 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); + 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; } -/** - * Set the rotation of an Ecore_Evas' window - * - * @param ee The Ecore_Evas - * @return the angle (in degrees) of rotation. - * - */ EAPI int -ecore_evas_rotation_get(Ecore_Evas *ee) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_rotation_get"); + return 0; } return ee->rotation; } -/** - * Set whether an Ecore_Evas is shaped or not. - * @param ee The Ecore_Evas to shape - * @param shaped 1 to shape, 0 to not - * - * This function allows one to make an Ecore_Evas shaped to the contents of the - * evas. If @p shaped is 1, @p ee will be transparent in parts of the evas that - * contain no objects. If @p shaped is 0, then @p ee will be rectangular, and - * and parts with no data will show random framebuffer artifacting. For - * non-shaped Ecore_Evases, it is recommend to cover the entire evas with a - * background object. - */ EAPI void -ecore_evas_shaped_set(Ecore_Evas *ee, int shaped) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_shaped_set"); + return; } IFC(ee, fn_shaped_set) (ee, shaped); IFE; } -/** - * Query whether an Ecore_Evas is shaped or not. - * @param ee The Ecore_Evas to query. - * @return 1 if shaped, 0 if not. - * - * This function returns 1 if @p ee is shaped, and 0 if not. - */ -EAPI int -ecore_evas_shaped_get(Ecore_Evas *ee) +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 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_shaped_get"); + return EINA_FALSE; } - return ee->shaped ? 1:0; + return ee->shaped ? EINA_TRUE : EINA_FALSE; } -/** - * Set whether an Ecore_Evas has an alpha channel or not. - * @param ee The Ecore_Evas to shape - * @param alpha 1 to enable the alpha channel, 0 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 transpararency, as opposed to - * the 1 bit transparency of a shaped window (a pixel is either opaque, or - * it's transparent). - */ EAPI void -ecore_evas_alpha_set(Ecore_Evas *ee, int alpha) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_alpha_set"); + return; } IFC(ee, fn_alpha_set) (ee, alpha); IFE; } -/** - * Query whether an Ecore_Evas has an alpha channel. - * @param ee The Ecore_Evas to query. - * @return 1 if ee has an alpha channel, 0 if it does not. - * - * This function returns 1 if @p ee has an alpha channel, and 0 if - * it does not. - */ -EAPI int -ecore_evas_alpha_get(Ecore_Evas *ee) +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 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_alpha_get"); + return EINA_FALSE; } - return ee->alpha ? 1:0; + 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; } -/** - * 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) { if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_show"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_show"); + return; } IFC(ee, fn_show) (ee); IFE; } -/** - * Hide an Ecore_Evas' window - * @param ee The Ecore_Evas to show. - * - * This function makes @p ee hidden. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_hide"); + return; } IFC(ee, fn_hide) (ee); IFE; } -/** - * 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. - */ -EAPI int -ecore_evas_visibility_get(Ecore_Evas *ee) + 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_visibility_get"); + return 0; } return ee->visible ? 1:0; } -/** - * Raise and Ecore_Evas' window. - * @param ee The Ecore_Evas to raise. - * - * This functions raises the Ecore_Evas to the front. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_raise"); + return; } IFC(ee, fn_raise) (ee); IFE; } -/** - * Lower an Ecore_Evas' window. - * @param ee The Ecore_Evas to raise. - * - * This functions lowers the Ecore_Evas to the back. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_lower"); + return; } IFC(ee, fn_lower) (ee); IFE; } -/** - * 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) { if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_activate"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_activate"); + return; } IFC(ee, fn_activate) (ee); IFE; } -/** - * 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. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_title_set"); + return; } IFC(ee, fn_title_set) (ee, t); IFE; } -/** - * 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. - */ EAPI const char * -ecore_evas_title_get(Ecore_Evas *ee) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_title_get"); + return NULL; } return ee->prop.title; } -/** - * 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. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_name_class_set"); + return; } IFC(ee, fn_name_class_set) (ee, n, c); IFE; } -/** - * Get the name and class of an Ecore_Evas' window - * @p ee The Ecore_Evas to query - * @p n A pointer to a string to place the name in. - * @p c A pointer to a string to place the class in. - * - * This function gets puts the name of @p ee into @p n, and its class into - * @p c. - */ EAPI void -ecore_evas_name_class_get(Ecore_Evas *ee, const char **n, const char **c) +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; + 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; } -/** - * Set the min size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @param w The minimum width - * @param h The minimum height - * - * This function sets the minimum size of @p ee to @p w x @p h. - */ 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; + 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; + IFC(ee, fn_size_min_set) (ee, h, w); + IFE; } else { - IFC(ee, fn_size_min_set) (ee, w, h); - IFE; + IFC(ee, fn_size_min_set) (ee, w, h); + IFE; } } -/** - * Get the min size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @param w A pointer to an int to place the min width in. - * @param h A pointer to an int to place the min height in. - * - * This function puts the minimum size of @p ee into @p w and @p h. - */ EAPI void -ecore_evas_size_min_get(Ecore_Evas *ee, int *w, int *h) +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; + 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; + 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; + if (w) *w = ee->prop.min.w; + if (h) *h = ee->prop.min.h; } } -/** - * Set the max size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @param w The maximum width - * @param h The maximum height - * - * This function sets the maximum size of @p ee to @p w x @p 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; + 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; + IFC(ee, fn_size_max_set) (ee, h, w); + IFE; } else { - IFC(ee, fn_size_max_set) (ee, w, h); - IFE; + IFC(ee, fn_size_max_set) (ee, w, h); + IFE; } } -/** - * Get the max size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @param w A pointer to an int to place the max width in. - * @param h A pointer to an int to place the max height in. - * - * This function puts the maximum size of @p ee into @p w and @p h. - */ EAPI void -ecore_evas_size_max_get(Ecore_Evas *ee, int *w, int *h) +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; + 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; + 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; + if (w) *w = ee->prop.max.w; + if (h) *h = ee->prop.max.h; } } -/** - * Set the base size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @param w The base width - * @param h The base height - * - * This function sets the base size of @p ee to @p w x @p 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; + 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; + IFC(ee, fn_size_base_set) (ee, h, w); + IFE; } else { - IFC(ee, fn_size_base_set) (ee, w, h); - IFE; + IFC(ee, fn_size_base_set) (ee, w, h); + IFE; } } -/** - * Get the base size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @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. - * - * This function puts the base size of @p ee into @p w and @p h. - */ EAPI void -ecore_evas_size_base_get(Ecore_Evas *ee, int *w, int *h) +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; + 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; + 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; + if (w) *w = ee->prop.base.w; + if (h) *h = ee->prop.base.h; } } -/** - * Set the step size of an Ecore_Evas - * @param ee The Ecore_Evas to set - * @param w The step width - * @param h The step height - * - * This function sets the step size of @p ee to @p w x @p h. This limits the - * size of an Ecore_Evas to always being an integer multiple of the step size. - */ 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; + 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; + IFC(ee, fn_size_step_set) (ee, h, w); + IFE; } else { - IFC(ee, fn_size_step_set) (ee, w, h); - IFE; + IFC(ee, fn_size_step_set) (ee, w, h); + IFE; } } -/** - * Get the step size of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @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. - * - * This function puts the step size of @p ee into @p w and @p h. - */ EAPI void -ecore_evas_size_step_get(Ecore_Evas *ee, int *w, int *h) +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; + 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; + 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; + if (w) *w = ee->prop.step.w; + if (h) *h = ee->prop.step.h; } } -/** - * 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 - * @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. - */ EAPI void ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, int hot_y) { @@ -1332,9 +1737,9 @@ ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, in if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_cursor_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_cursor_set"); + return; } if (file) @@ -1352,50 +1757,27 @@ ecore_evas_cursor_set(Ecore_Evas *ee, const char *file, int layer, int hot_x, in IFE; } -/** - * Set the cursor of an Ecore_Evas - * @param ee The Ecore_Evas - * @param obj The Evas_Object for the cursor - * @param layer - * @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. - */ 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; + 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; } -/** - * 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. - */ EAPI void -ecore_evas_cursor_get(Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, int *hot_y) +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; + 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; @@ -1403,447 +1785,593 @@ ecore_evas_cursor_get(Ecore_Evas *ee, Evas_Object **obj, int *layer, int *hot_x, if (hot_y) *hot_y = ee->prop.cursor.hot.y; } -/** - * 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. - */ 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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_layer_set"); + return; } IFC(ee, fn_layer_set) (ee, layer); IFE; } -/** - * Get the layer of an Ecore_Evas' window - * @param ee The Ecore_Evas to set - * @return the layer @p ee's window is on. - * - */ EAPI int -ecore_evas_layer_get(Ecore_Evas *ee) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_layer_get"); + return 0; } return ee->prop.layer; } -/** - * Set the focus of an Ecore_Evas' window - * @param ee The Ecore_Evas - * @param on 1 for focus, 0 to defocus. - * - * This function focuses @p ee if @p on is 1, or defocuses @p ee if @p on is 0. - */ EAPI void -ecore_evas_focus_set(Ecore_Evas *ee, int on) +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; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_focus_set"); + return; } IFC(ee, fn_focus_set) (ee, on); IFE; } -/** - * Query whether an Ecore_Evas' window is focused or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee if focused, 0 if not. - * - */ -EAPI int -ecore_evas_focus_get(Ecore_Evas *ee) +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_profiles_set(Ecore_Evas *ee, const char **profiles, unsigned int num_profiles) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_profiles_set"); + return; + } + IFC(ee, fn_profiles_set) (ee, profiles, num_profiles); + IFE; +} + +EAPI const char * +ecore_evas_profile_get(const Ecore_Evas *ee) +{ + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_profile_get"); + return NULL; + } + return ee->prop.profile; +} + +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, - "ecore_evas_focus_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; } - return ee->prop.focused ? 1:0; + return ee->prop.urgent ? EINA_TRUE : EINA_FALSE; } -/** - * Iconify or uniconify an Ecore_Evas' window - * @param ee The Ecore_Evas - * @param on 1 to iconify, 0 to uniconify. - * - * This function iconifies @p ee if @p on is 1, or uniconifies @p ee if @p on - * is 0. - */ EAPI void -ecore_evas_iconified_set(Ecore_Evas *ee, int on) +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, - "ecore_evas_iconified_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; } - IFC(ee, fn_iconified_set) (ee, on); + + IFC(ee, fn_modal_set) (ee, modal); IFE; } -/** - * Query whether an Ecore_Evas' window is iconified or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee is iconified, 0 if not. - * - */ -EAPI int -ecore_evas_iconified_get(Ecore_Evas *ee) +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, - "ecore_evas_iconified_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; } - return ee->prop.iconified ? 1:0; + return ee->prop.modal ? EINA_TRUE : EINA_FALSE; } -/** - * Set whether an Ecore_Evas' window is borderless or not - * @param ee The Ecore_Evas - * @param on 1 for borderless, 0 for bordered. - * - * This function makes @p ee borderless if @p on is 1, or bordered if @p on - * is 0. - */ EAPI void -ecore_evas_borderless_set(Ecore_Evas *ee, int on) +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, - "ecore_evas_borderless_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; } - IFC(ee, fn_borderless_set) (ee, on); + + IFC(ee, fn_demands_attention_set) (ee, demand); IFE; } -/** - * Query whether an Ecore_Evas' window is borderless or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee is borderless, 0 if not. - * - */ -EAPI int -ecore_evas_borderless_get(Ecore_Evas *ee) +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, - "ecore_evas_borderless_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; } - return ee->prop.borderless ? 1:0; + return ee->prop.demand_attention ? EINA_TRUE : EINA_FALSE; } -/** - * Tell the WM whether or not to ignore an Ecore_Evas' window - * @param ee The Ecore_Evas - * @param on 1 to ignore, 0 to not. - * - * This function causes the window manager to ignore @p ee if @p on is 1, - * or not ignore @p ee if @p on is 0. - */ EAPI void -ecore_evas_override_set(Ecore_Evas *ee, int on) +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, - "ecore_evas_override_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return; } - IFC(ee, fn_override_set) (ee, on); + + IFC(ee, fn_focus_skip_set) (ee, skip); IFE; } -/** - * Query whether an Ecore_Evas' window is overridden or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee is overridden, 0 if not. - * - */ -EAPI int -ecore_evas_override_get(Ecore_Evas *ee) +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, - "ecore_evas_override_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "XXX"); + return EINA_FALSE; } - return ee->prop.override ? 1:0; + return ee->prop.focus_skip ? EINA_TRUE : EINA_FALSE; } -/** - * Maximize (or unmaximize) an Ecore_Evas' window - * @param ee The Ecore_Evas - * @param on 1 to maximize, 0 to unmaximize. - * - * This function maximizes @p ee if @p on is 1, or unmaximizes @p ee - * if @p on is 0. - */ EAPI void -ecore_evas_maximized_set(Ecore_Evas *ee, int on) +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_maximized_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ignore_events_set"); + return; } - IFC(ee, fn_maximized_set) (ee, on); + + IFC(ee, fn_ignore_events_set) (ee, ignore); IFE; } -/** - * Query whether an Ecore_Evas' window is maximized or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee is maximized, 0 if not. - * - */ -EAPI int -ecore_evas_maximized_get(Ecore_Evas *ee) +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_maximized_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_ignore_events_get"); + return EINA_FALSE; } - return ee->prop.maximized ? 1:0; + return ee->ignore_events ? EINA_TRUE : EINA_FALSE; } -/** - * Set whether or not an Ecore_Evas' window is fullscreen - * @param ee The Ecore_Evas - * @param on 1 fullscreen, 0 not. - * - * This function causes @p ee to be fullscreen if @p on is 1, - * or not if @p on is 0. - */ EAPI void -ecore_evas_fullscreen_set(Ecore_Evas *ee, int on) +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_fullscreen_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render_set"); + return; } - IFC(ee, fn_fullscreen_set) (ee, on); - IFE; + ee->manual_render = manual_render; } -/** - * Query whether an Ecore_Evas' window is fullscreen or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee is fullscreen, 0 if not. - * - */ -EAPI int -ecore_evas_fullscreen_get(Ecore_Evas *ee) +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_fullscreen_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render_get"); + return EINA_FALSE; } - return ee->prop.fullscreen ? 1:0; + return ee->manual_render ? EINA_TRUE : EINA_FALSE; } -/** - * Set whether or not an Ecore_Evas' window should avoid damage - * - * @param ee The Ecore_Evas - * @param on 1 to avoid damage, 0 to not - * - * This function causes @p ee to be drawn to a pixmap to avoid recalculations. - * On expose events it will copy from the pixmap to the window. - */ EAPI void -ecore_evas_avoid_damage_set(Ecore_Evas *ee, Ecore_Evas_Avoid_Damage_Type on) +ecore_evas_manual_render(Ecore_Evas *ee) { if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_avoid_damage_set"); - return; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_manual_render"); + return; } - IFC(ee, fn_avoid_damage_set) (ee, on); - IFE; + if (ee->engine.func->fn_render) + ee->engine.func->fn_render(ee); } -/** - * Query whether an Ecore_Evas' window avoids damage or not - * @param ee The Ecore_Evas to set - * @return 1 if @p ee avoids damage, 0 if not. - * - */ -EAPI Ecore_Evas_Avoid_Damage_Type -ecore_evas_avoid_damage_get(Ecore_Evas *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_avoid_damage_get"); - return 0; + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_comp_sync_set"); + return; } - return ee->prop.avoid_damage; + ee->no_comp_sync = !do_sync; } -/** - * 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, int withdrawn) +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_withdrawn_set"); - return; - } - - IFC(ee, fn_withdrawn_set) (ee, withdrawn); - IFE; + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_comp_sync_get"); + return EINA_FALSE; + } + return !ee->no_comp_sync; } -/** - * 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 int -ecore_evas_withdrawn_get(Ecore_Evas *ee) +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_withdrawn_get"); + "ecore_evas_window_get"); return 0; - } else - return ee->prop.withdrawn ? 1:0; + } + + return ee->prop.window; } -/** - * 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, int sticky) +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_sticky_set"); - return; - } + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_screen_geometry_get"); + return; + } - IFC(ee, fn_sticky_set) (ee, sticky); + IFC(ee, fn_screen_geometry_get) (ee, x, y, w, h); IFE; } -/** - * 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 int -ecore_evas_sticky_get(Ecore_Evas *ee) -{ - if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) - { - ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, - "ecore_evas_sticky_get"); - return 0; - } else - return ee->prop.sticky ? 1:0; -} - -/** - * Set if this evas should ignore events - * - * @param ee The Ecore_Evas whose window's to ignore events - * @param sticky The Ecore_Evas new ignore state - * - */ EAPI void -ecore_evas_ignore_events_set(Ecore_Evas *ee, int ignore) +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_ignore_events_set"); - return; - } + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, + "ecore_evas_screen_geometry_get"); + return; + } - IFC(ee, fn_ignore_events_set) (ee, ignore); + IFC(ee, fn_screen_dpi_get) (ee, xdpi, ydpi); IFE; } -/** - * 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. - * - */ -EAPI int -ecore_evas_ignore_events_get(Ecore_Evas *ee) +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_ignore_events_get"); - return 0; - } else - return ee->ignore_events ? 1 : 0; + { + ECORE_MAGIC_FAIL(ee, ECORE_MAGIC_EVAS, "ecore_evas_draw_frame_set"); + return; + } + ee->prop.draw_frame = draw_frame; } -EAPI void * -ecore_evas_window_get(Ecore_Evas *ee) +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_window_get"); - return NULL; - } - - if (ee->engine.func->fn_window_get) return ee->engine.func->fn_window_get(ee); - return NULL; + { + 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 */ @@ -1857,27 +2385,54 @@ 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; - snprintf(buf, sizeof(buf), "/tmp/.ecore_evas_fps_debug-%i", (int)getpid()); + +#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); + 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; - - write(_ecore_evas_fps_debug_fd, &zero, sizeof(unsigned int)); - _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; + 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; } } @@ -1888,69 +2443,115 @@ _ecore_evas_fps_debug_shutdown(void) if (_ecore_evas_fps_debug_init_count > 0) return; if (_ecore_evas_fps_debug_fd >= 0) { - char buf[4096]; + 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; + 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) { - if ((_ecore_evas_fps_debug_fd >= 0) && - (_ecore_evas_fps_rendertime_mmap)) + 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) { - unsigned int tm; + 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++; +} - 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_evas_fps_rendertime_mmap) += tm; +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) { - ECORE_MAGIC_SET(ee, ECORE_MAGIC_NONE); + 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); + _ecore_evas_free(ee->sub_ecore_evas->data); } - if (ee->data) evas_hash_free(ee->data); - if (ee->name) free(ee->name); - if (ee->prop.title) free(ee->prop.title); - if (ee->prop.name) free(ee->prop.name); - if (ee->prop.clas) free(ee->prop.clas); - if (ee->prop.cursor.object) evas_object_del(ee->prop.cursor.object); - if (ee->evas) evas_free(ee->evas); + if (ee->data) eina_hash_free(ee->data); ee->data = NULL; - ee->driver = 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 int +static Eina_Bool _ecore_evas_cb_idle_flush(void *data) { Ecore_Evas *ee; @@ -1958,7 +2559,15 @@ _ecore_evas_cb_idle_flush(void *data) ee = (Ecore_Evas *)data; evas_render_idle_flush(ee->evas); ee->engine.idle_flush_timer = NULL; - return 0; + 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 @@ -1967,6 +2576,305 @@ _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); + _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 (!strncmp(ee->driver, "wayland", 7)) + { + if (ee->engine.wl.win) + { + ee->engine.wl.win->moving = EINA_TRUE; + ecore_wl_window_move(ee->engine.wl.win, x, y); + } + } +} + +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 __UNUSED__, int hot_x __UNUSED__, int hot_y __UNUSED__) +{ + +} + +#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 index c1df0fe..77ee8c1 100644 --- a/src/lib/ecore_evas/ecore_evas_buffer.c +++ b/src/lib/ecore_evas/ecore_evas_buffer.c @@ -1,62 +1,56 @@ - #ifdef HAVE_CONFIG_H # include #endif -#include "Ecore.h" +// 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_BUFFER +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER static int _ecore_evas_init_count = 0; -static int _ecore_evas_fps_debug = 0; - -static Ecore_Evas *ecore_evases = NULL; - -static void -_ecore_evas_mouse_move_process(Ecore_Evas *ee, int x, int y, unsigned int timestamp) -{ - ee->mouse.x = x; - ee->mouse.y = y; - evas_event_feed_mouse_move(ee->evas, x, y, timestamp, NULL); -} - static int _ecore_evas_buffer_init(void) { _ecore_evas_init_count++; - if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); return _ecore_evas_init_count; } static void _ecore_evas_buffer_free(Ecore_Evas *ee) { - ecore_evases = _ecore_list2_remove(ecore_evases, ee); - _ecore_evas_buffer_shutdown(); if (ee->engine.buffer.image) { - Ecore_Evas *ee2; + 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 = evas_list_remove(ee2->sub_ecore_evas, ee); + 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 - free(ee->engine.buffer.pixels); + { + 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; @@ -66,154 +60,226 @@ _ecore_evas_resize(Ecore_Evas *ee, int w, int h) if (ee->engine.buffer.image) { - ee->engine.buffer.pixels = evas_object_image_data_get(ee->engine.buffer.image, 1); + 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) free(ee->engine.buffer.pixels); - ee->engine.buffer.pixels = malloc(ee->w * ee->h * sizeof(int)); + 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) { - einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; - 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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) - { - while (ecore_evases) - { - _ecore_evas_free((Ecore_Evas *)ecore_evases); - } - 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; } -void +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) { - Evas_List *updates, *l, *ll; + Eina_List *updates = NULL, *l, *ll; + Ecore_Evas *ee2; + int rend = 0; - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) { - Ecore_Evas *ee2; - - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(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; + 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); + 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); } - updates = evas_render_updates(ee->evas); if (ee->engine.buffer.image) { - for (l = updates; l; l = l->next) - { - Evas_Rectangle *r; - - r = l->data; - if (ee->engine.buffer.image) - evas_object_image_data_update_add(ee->engine.buffer.image, - r->x, r->y, r->w, r->h); - } + 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); + 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, fx, fy, fw, fh; + Evas_Coord xx, yy, ww, hh, fx, fy, fw, fh; - evas_object_geometry_get(ee->engine.buffer.image, &xx, &yy, NULL, NULL); + 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; - xx = (*x - xx) - fx; - while (xx < 0) xx += fw; - while (xx > fw) xx -= fw; - *x = (ee->w * xx) / fw; - if (fh < 1) fh = 1; - yy = (*y - yy) - fy; - while (yy < 0) yy += fh; - while (yy > fh) yy -= fh; - *y = (ee->h * yy) / fh; + + 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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +_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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +_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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +_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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +_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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +_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; @@ -224,21 +290,86 @@ _ecore_evas_buffer_cb_mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *ob 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 __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +_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; @@ -255,42 +386,7 @@ _ecore_evas_buffer_cb_key_down(void *data, Evas *e, Evas_Object *obj __UNUSED__, ee = data; ev = event_info; - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift")) - evas_key_modifier_on(e, "Shift"); - else - evas_key_modifier_off(e, "Shift"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control")) - evas_key_modifier_on(e, "Control"); - else - evas_key_modifier_off(e, "Control"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt")) - evas_key_modifier_on(e, "Alt"); - else - evas_key_modifier_off(e, "Alt"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta")) - evas_key_modifier_on(e, "Meta"); - else - evas_key_modifier_off(e, "Meta"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper")) - evas_key_modifier_on(e, "Hyper"); - else - evas_key_modifier_off(e, "Hyper"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super")) - evas_key_modifier_on(e, "Super"); - else - evas_key_modifier_off(e, "Super"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock")) - evas_key_lock_on(e, "Scroll_Lock"); - else - evas_key_lock_off(e, "Scroll_Lock"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock")) - evas_key_lock_on(e, "Num_Lock"); - else - evas_key_lock_off(e, "Num_Lock"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock")) - evas_key_lock_on(e, "Caps_Lock"); - else - evas_key_lock_off(e, "Caps_Lock"); + _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); } @@ -302,42 +398,7 @@ _ecore_evas_buffer_cb_key_up(void *data, Evas *e, Evas_Object *obj __UNUSED__, v ee = data; ev = event_info; - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Shift")) - evas_key_modifier_on(e, "Shift"); - else - evas_key_modifier_off(e, "Shift"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Control")) - evas_key_modifier_on(e, "Control"); - else - evas_key_modifier_off(e, "Control"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Alt")) - evas_key_modifier_on(e, "Alt"); - else - evas_key_modifier_off(e, "Alt"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Meta")) - evas_key_modifier_on(e, "Meta"); - else - evas_key_modifier_off(e, "Meta"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Hyper")) - evas_key_modifier_on(e, "Hyper"); - else - evas_key_modifier_off(e, "Hyper"); - if (evas_key_modifier_is_set(evas_key_modifier_get(e), "Super")) - evas_key_modifier_on(e, "Super"); - else - evas_key_modifier_off(e, "Super"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Scroll_Lock")) - evas_key_lock_on(e, "Scroll_Lock"); - else - evas_key_lock_off(e, "Scroll_Lock"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Num_Lock")) - evas_key_lock_on(e, "Num_Lock"); - else - evas_key_lock_off(e, "Num_Lock"); - if (evas_key_lock_is_set(evas_key_lock_get(e), "Caps_Lock")) - evas_key_lock_on(e, "Caps_Lock"); - else - evas_key_lock_off(e, "Caps_Lock"); + _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); } @@ -348,6 +409,7 @@ _ecore_evas_buffer_cb_focus_in(void *data, Evas *e __UNUSED__, Evas_Object *obj ee = data; ee->prop.focused = 1; + evas_focus_in(ee->evas); if (ee->func.fn_focus_in) ee->func.fn_focus_in(ee); } @@ -358,6 +420,7 @@ _ecore_evas_buffer_cb_focus_out(void *data, Evas *e __UNUSED__, Evas_Object *obj ee = data; ee->prop.focused = 0; + evas_focus_out(ee->evas); if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); } @@ -381,7 +444,30 @@ _ecore_evas_buffer_cb_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UN if (ee->func.fn_hide) ee->func.fn_hide(ee); } -static const Ecore_Evas_Engine_Func _ecore_buffer_engine_func = +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, @@ -401,8 +487,10 @@ static const Ecore_Evas_Engine_Func _ecore_buffer_engine_func = NULL, NULL, _ecore_evas_resize, + _ecore_evas_move_resize, NULL, NULL, + _ecore_evas_show, NULL, NULL, NULL, @@ -425,26 +513,52 @@ static const Ecore_Evas_Engine_Func _ecore_buffer_engine_func = NULL, NULL, NULL, + _ecore_evas_buffer_alpha_set, + NULL, //transparent + NULL, // profiles_set + NULL, NULL, NULL, - NULL + NULL, + NULL, + NULL, + + _ecore_evas_buffer_render, + NULL, // screen_geometry_get + NULL // screen_dpi_get }; #endif -/** - * To be documented. - * - * FIXME: To be fixed. - */ +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) { -#ifdef BUILD_ECORE_EVAS_BUFFER + 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)); @@ -455,6 +569,9 @@ ecore_evas_buffer_new(int w, int h) _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"; @@ -464,6 +581,8 @@ ecore_evas_buffer_new(int w, int h) 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; @@ -483,19 +602,32 @@ ecore_evas_buffer_new(int w, int h) evas_output_size_set(ee->evas, w, h); evas_output_viewport_set(ee->evas, 0, 0, w, h); - ee->engine.buffer.pixels = malloc(w * h * sizeof(int)); + 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_ARGB32; - 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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"); @@ -509,17 +641,25 @@ ecore_evas_buffer_new(int w, int h) evas_event_feed_mouse_in(ee->evas, 0, NULL); - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); + _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 int * +EAPI const void * ecore_evas_buffer_pixels_get(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_BUFFER +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER + if (!ee) + { + CRIT("Ecore_Evas is missing"); + return NULL; + } _ecore_evas_buffer_render(ee); return ee->engine.buffer.pixels; #else @@ -527,15 +667,35 @@ ecore_evas_buffer_pixels_get(Ecore_Evas *ee) #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) { -#ifdef BUILD_ECORE_EVAS_BUFFER +// 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, h; + int w = 1, h = 1; + + if (!ee_target) return NULL; rmethod = evas_render_method_lookup("buffer"); if (!rmethod) return NULL; @@ -543,6 +703,10 @@ ecore_evas_object_image_new(Ecore_Evas *ee_target) 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); @@ -552,12 +716,12 @@ ecore_evas_object_image_new(Ecore_Evas *ee_target) ee->driver = "buffer"; - w = 1; - h = 1; 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; @@ -580,60 +744,78 @@ ecore_evas_object_image_new(Ecore_Evas *ee_target) 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_image_size_set(o, ee->w, ee->h); - evas_object_image_alpha_set(o, 1); - ee->engine.buffer.pixels = evas_object_image_data_get(o, 1); - evas_object_image_data_set(o, ee->engine.buffer.pixels); evas_object_event_callback_add(ee->engine.buffer.image, - EVAS_CALLBACK_MOUSE_IN, - _ecore_evas_buffer_cb_mouse_in, ee); + 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_OUT, - _ecore_evas_buffer_cb_mouse_out, ee); + EVAS_CALLBACK_MOUSE_MOVE, + _ecore_evas_buffer_cb_mouse_move, ee); evas_object_event_callback_add(ee->engine.buffer.image, - EVAS_CALLBACK_MOUSE_DOWN, - _ecore_evas_buffer_cb_mouse_down, ee); + EVAS_CALLBACK_MOUSE_WHEEL, + _ecore_evas_buffer_cb_mouse_wheel, ee); evas_object_event_callback_add(ee->engine.buffer.image, - EVAS_CALLBACK_MOUSE_UP, - _ecore_evas_buffer_cb_mouse_up, ee); + EVAS_CALLBACK_MULTI_DOWN, + _ecore_evas_buffer_cb_multi_down, ee); evas_object_event_callback_add(ee->engine.buffer.image, - EVAS_CALLBACK_MOUSE_MOVE, - _ecore_evas_buffer_cb_mouse_move, ee); + EVAS_CALLBACK_MULTI_UP, + _ecore_evas_buffer_cb_multi_up, ee); evas_object_event_callback_add(ee->engine.buffer.image, - EVAS_CALLBACK_MOUSE_WHEEL, - _ecore_evas_buffer_cb_mouse_wheel, ee); + 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_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_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_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_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_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_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); + EVAS_CALLBACK_HIDE, + _ecore_evas_buffer_cb_hide, ee); einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ee->evas); if (einfo) { - einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32; - 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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"); @@ -645,7 +827,8 @@ ecore_evas_object_image_new(Ecore_Evas *ee_target) evas_key_lock_add(ee->evas, "Num_Lock"); evas_key_lock_add(ee->evas, "Scroll_Lock"); - ee_target->sub_ecore_evas = evas_list_append(ee_target->sub_ecore_evas, ee); + ee_target->sub_ecore_evas = eina_list_append(ee_target->sub_ecore_evas, ee); + return o; #else return NULL; 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 index 23723d9..d9fb237 100644 --- a/src/lib/ecore_evas/ecore_evas_directfb.c +++ b/src/lib/ecore_evas/ecore_evas_directfb.c @@ -1,83 +1,59 @@ -#include "config.h" -#include "Ecore.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include #include "ecore_private.h" -#include "ecore_evas_private.h" -#include "Ecore_Evas.h" #ifdef BUILD_ECORE_EVAS_DIRECTFB -#include "Ecore_DirectFB.h" +#include #endif +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" #ifdef BUILD_ECORE_EVAS_DIRECTFB static int _ecore_evas_init_count = 0; -static int _ecore_evas_fps_debug = 0; static Ecore_Event_Handler *ecore_evas_event_handlers[13]; -static Ecore_Evas *ecore_evases = NULL; -static Evas_Hash *ecore_evases_hash = NULL; - -static Ecore_Idle_Enterer *ecore_evas_directfb_idle_enterer = NULL; +static Eina_Hash *ecore_evases_hash = NULL; -static void +static int _ecore_evas_directfb_render(Ecore_Evas *ee) { - Evas_List *updates, *ll; - -#ifdef BUILD_ECORE_EVAS_BUFFER - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) + Eina_List *updates, *ll; + Ecore_Evas *ee2; + int rend = 0; + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) { - Ecore_Evas *ee2; - - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(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); } -#endif + 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); + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); } if (ee->func.fn_post_render) ee->func.fn_post_render(ee); -} -static int -_ecore_evas_directfb_idle_enter(void *data __UNUSED__) -{ - Ecore_List2 *l; - double t1 = 0.; - double t2 = 0.; - - if (_ecore_evas_fps_debug) - { - t1 = ecore_time_get(); - } - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - _ecore_evas_directfb_render(ee); - } - if (_ecore_evas_fps_debug) - { - t2 = ecore_time_get(); - _ecore_evas_fps_debug_rendertime_add(t2 - t1); - } - return 1; + return updates ? 1 : rend; } static char * _ecore_evas_directfb_winid_str_get(Ecore_X_Window win) { - const char *vals = "qWeRtYuIoP5-$&<~"; + const char *vals = "qWeRtYuIoP5$&<~"; static char id[9]; - unsigned int val; + unsigned int val; val = (unsigned int)win; - id[0] = vals[(val >> 28) & 0xf]; + id[0] = vals[(val >> 28) & 0xf]; id[1] = vals[(val >> 24) & 0xf]; id[2] = vals[(val >> 20) & 0xf]; id[3] = vals[(val >> 16) & 0xf]; @@ -89,217 +65,179 @@ _ecore_evas_directfb_winid_str_get(Ecore_X_Window win) return id; } - static Ecore_Evas * _ecore_evas_directfb_match(DFBWindowID win) -{ +{ Ecore_Evas *ee; - - ee = evas_hash_find(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(win)); + + ee = eina_hash_find(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(win)); return ee; } - -static void -_ecore_evas_directfb_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); -} - -static int +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 1; /* pass on event */ - evas_event_feed_key_down(ee->evas, e->name, NULL, e->string, e->key_compose, e->time, NULL); - return 1; + + 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 int +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 1; /* pass on event */ - evas_event_feed_key_up(ee->evas, e->name, NULL, e->string, e->key_compose, e->time, NULL); - return 1; + + 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 int +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 1; /* pass on event */ - _ecore_evas_directfb_mouse_move_process(ee, e->x, e->y, e->time); - return 1; + + if (!ee) return EINA_TRUE; /* pass on event */ + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + return EINA_TRUE; } -static int +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 1; /* pass on event */ - // _ecore_evas_directfb_mouse_move_process(ee, e->x, e->y, e->time); + + 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 1; + return EINA_TRUE; } -static int +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 1; /* pass on event */ - //_ecore_evas_directfb_mouse_move_process(ee, e->x, e->y, e->time); + + 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 1; + return EINA_TRUE; } -static int +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 1; /* pass on event */ + + if (!ee) return EINA_TRUE; /* pass on event */ evas_event_feed_mouse_in(ee->evas, e->time, NULL); - //_ecore_evas_directfb_mouse_move_process(ee, e->x, e->y, e->time); - return 1; + //_ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); + return EINA_TRUE; } -static int +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 1; /* pass on event */ + + if (!ee) return EINA_TRUE; /* pass on event */ evas_event_feed_mouse_out(ee->evas, e->time, NULL); - //_ecore_evas_directfb_mouse_move_process(ee, e->x, e->y, e->time); + //_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 1; + return EINA_TRUE; } -static int +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 1; /* pass on event */ + + if (!ee) return EINA_TRUE; /* pass on event */ evas_event_feed_mouse_wheel(ee->evas, e->direction, e->z, e->time, NULL); - return 1; + return EINA_TRUE; } -static int +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 1; /* pass on event */ + + if (!ee) return EINA_TRUE; /* pass on event */ ee->prop.focused = 1; - return 1; + return EINA_TRUE; } -static int +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 1; /* pass on event */ + + if (!ee) return EINA_TRUE; /* pass on event */ ee->prop.focused = 0; - return 1; + return EINA_TRUE; } - + int _ecore_evas_directfb_shutdown(void) { _ecore_evas_init_count--; if (_ecore_evas_init_count == 0) { - int i; - - while (ecore_evases) _ecore_evas_free(ecore_evases); - for (i = 0; i < 8; i++) - ecore_event_handler_del(ecore_evas_event_handlers[i]); - ecore_idle_enterer_del(ecore_evas_directfb_idle_enterer); - ecore_evas_directfb_idle_enterer = NULL; - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); + 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; } - + @@ -309,10 +247,7 @@ _ecore_evas_directfb_init(void) { _ecore_evas_init_count++; if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; - ecore_evas_directfb_idle_enterer = ecore_idle_enterer_add(_ecore_evas_directfb_idle_enter, NULL); - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); - + 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); @@ -326,19 +261,18 @@ _ecore_evas_directfb_init(void) 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) { - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee); - ecore_directfb_window_del(ee->engine.directfb.window); - ecore_evases = _ecore_list2_remove(ecore_evases, 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(); } @@ -349,22 +283,24 @@ _ecore_evas_directfb_move(Ecore_Evas *ee, int x, int y) ecore_directfb_window_move(ee->engine.directfb.window, x, y); } -static void +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); + 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); + evas_output_size_set(ee->evas, ee->w, ee->h); + evas_output_viewport_set(ee->evas, 0, 0, ee->w, ee->h); } } @@ -398,25 +334,35 @@ _ecore_evas_directfb_shaped_set(Ecore_Evas *ee, int 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 == NULL) + 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 = 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; @@ -432,6 +378,8 @@ _ecore_evas_directfb_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int lay 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 @@ -441,10 +389,10 @@ _ecore_evas_directfb_fullscreen_set(Ecore_Evas *ee, int on) int w; int h; int resized = 0; - - if (((ee->prop.fullscreen) && (on)) || ((!ee->prop.fullscreen) && (!on))) + + if (((ee->prop.fullscreen) && (on)) || ((!ee->prop.fullscreen) && (!on))) return; - + if (on) ecore_directfb_window_fullscreen_set(ee->engine.directfb.window, 1); else @@ -453,139 +401,150 @@ _ecore_evas_directfb_fullscreen_set(Ecore_Evas *ee, int on) 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; - 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); - } + 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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); + if(ee->func.fn_resize) ee->func.fn_resize(ee); } } -#endif static void * -_ecore_evas_directfb_window_get(Ecore_Evas *ee) +_ecore_evas_directfb_window_get(const Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_DIRECTFB return ee->engine.directfb.window; -#else - return 0; -#endif } +#endif #ifdef BUILD_ECORE_EVAS_DIRECTFB -static const Ecore_Evas_Engine_Func _ecore_directfb_engine_func = +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 */ + _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, /* 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 */ + _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_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 */ + 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, /* avoid damage */ + NULL, /* withdrawn */ + NULL, /* sticky */ NULL, /* ignore events */ NULL, /* alpha */ - _ecore_evas_directfb_window_get /* window_get */ + NULL, //transparent + NULL, // profiles_set + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + NULL, // render + NULL, // screen_geometry_get + NULL // screen_dpi_get }; #endif /* api */ /*******/ -Ecore_DirectFB_Window * -ecore_evas_directfb_window_get(Ecore_Evas *ee) -{ - return (Ecore_DirectFB_Window *) _ecore_evas_directfb_window_get(ee); -} - +#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) { -#ifdef BUILD_ECORE_EVAS_DIRECTFB 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->prop.layer = 1; + 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); @@ -593,22 +552,55 @@ ecore_evas_directfb_new(const char *disp_name, int windowed, int x, int y, int w 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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; + } } - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_directfb_winid_str_get(ee->engine.directfb.window->id), ee); - + 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 - disp_name = NULL; - windowed = x = y = w = h = 0; +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 } +#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..6113539 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_extn.c @@ -0,0 +1,2247 @@ +#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 +///Jiyoun: This code will be modified after opensource fix lockup issue +#define EVAS_CALLBACK_CANVAS_OBJECT_RENDER_PRE 100 +#define EVAS_CALLBACK_CANVAS_OBJECT_RENDER_POST 101 + +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); +/*///Jiyoun: This code will be modified after opensource fix lockup issue + 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_event_callback_del_full(ee->engine.buffer.image, + EVAS_CALLBACK_CANVAS_OBJECT_RENDER_PRE, + _ecore_evas_extn_plug_targer_render_pre, + ee); + evas_object_event_callback_del_full(ee->engine.buffer.image, + EVAS_CALLBACK_CANVAS_OBJECT_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); + +/*///Jiyoun: This code will be modified after opensource fix lockup issue + 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); +*/ + evas_object_event_callback_add(ee->engine.buffer.image, EVAS_CALLBACK_CANVAS_OBJECT_RENDER_PRE, + _ecore_evas_extn_plug_targer_render_pre, ee); + evas_object_event_callback_add(ee->engine.buffer.image, EVAS_CALLBACK_CANVAS_OBJECT_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; + + if (!svcname) + { + ee->engine.buffer.data = NULL; + 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) + { + ee->engine.buffer.data = NULL; + 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; + if (!extn) return rend; + 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 index f29eaad..a8200a9 100644 --- a/src/lib/ecore_evas/ecore_evas_fb.c +++ b/src/lib/ecore_evas/ecore_evas_fb.c @@ -1,329 +1,253 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -#include "config.h" -#include "Ecore.h" +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include #include "ecore_private.h" -#include "ecore_evas_private.h" -#include "Ecore_Evas.h" #ifdef BUILD_ECORE_EVAS_FB -#include "Ecore_Fb.h" -#include "ecore_fb_private.h" +#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 int _ecore_evas_fps_debug = 0; static char *ecore_evas_default_display = "0"; -static Ecore_List *ecore_evas_input_devices = NULL; -static Ecore_Evas *ecore_evases = NULL; -static Ecore_Event_Handler *ecore_evas_event_handlers[6] = {NULL, NULL, NULL, NULL, NULL, NULL}; -static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; +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(Ecore_Evas *ee, int x, int y, unsigned int timestamp) +_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); + 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); + 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); } - 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, (fbh - ee->h) + ee->h - y - 1, x, timestamp, NULL); - else if (ee->rotation == 180) - evas_event_feed_mouse_move(ee->evas, (fbw - ee->w) + ee->w - x - 1, (fbh - ee->h) + ee->h - y - 1, timestamp, NULL); - else if (ee->rotation == 270) - evas_event_feed_mouse_move(ee->evas, y, (fbw - ee->w) + ee->w - x - 1, timestamp, NULL); } +static Ecore_Evas *fb_ee = NULL; + static Ecore_Evas * _ecore_evas_fb_match(void) { - return ecore_evases; + return fb_ee; } static void _ecore_evas_fb_lose(void *data __UNUSED__) { - Ecore_List2 *l; + Eina_List *ll; Ecore_Fb_Input_Device *dev; - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - ee->visible = 0; - } - if (ecore_evas_input_devices) - { - ecore_list_first_goto(ecore_evas_input_devices); - while ((dev = ecore_list_next(ecore_evas_input_devices))) - ecore_fb_input_device_listen(dev, 0); - } + 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_List2 *l; + Ecore_Evas *ee; + Eina_List *ll; Ecore_Fb_Input_Device *dev; - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - 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); - } - if (ecore_evas_input_devices) + if (fb_ee) { - ecore_list_first_goto(ecore_evas_input_devices); - while ((dev = ecore_list_next(ecore_evas_input_devices))) - ecore_fb_input_device_listen(dev, 1); - } -} + ee = fb_ee; -static int -_ecore_evas_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Fb_Event_Key_Down *e; - - e = event; - ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - evas_event_feed_key_down(ee->evas, e->keyname, e->keysymbol, e->key_compose, NULL, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); - return 0; /* dont pass it on */ -} + 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); + } -static int -_ecore_evas_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Fb_Event_Key_Up *e; - - e = event; - ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - evas_event_feed_key_up(ee->evas, e->keyname, e->keysymbol, e->key_compose, NULL, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); - return 0; /* dont pass it on */ + EINA_LIST_FOREACH(ecore_evas_input_devices, ll, dev) + ecore_fb_input_device_listen(dev, 1); } -static int +static Eina_Bool _ecore_evas_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_Fb_Event_Mouse_Button_Down *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - + Ecore_Event_Mouse_Button *e; + e = event; ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff)); - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_down(ee->evas, e->button, flags, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); - return 0; /* dont pass it on */ + 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 +static Eina_Bool _ecore_evas_event_mouse_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_Fb_Event_Mouse_Button_Up *e; - + Ecore_Event_Mouse_Button *e; + e = event; ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff)); - evas_event_feed_mouse_up(ee->evas, e->button, EVAS_BUTTON_NONE, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL); - return 0; /* dont pass it on */ + 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 +static Eina_Bool _ecore_evas_event_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_Fb_Event_Mouse_Move *e; - + Ecore_Event_Mouse_Move *e; + e = event; ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff)); - return 0; /* dont pass it on */ + 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 +static Eina_Bool _ecore_evas_event_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_Fb_Event_Mouse_Wheel *e; - + Ecore_Event_Mouse_Wheel *e; + e = event; ee = _ecore_evas_fb_match(); - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff)); - return 0; /* dont pass it on */ + 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_idle_enter(void *data __UNUSED__) +_ecore_evas_fb_render(Ecore_Evas *ee) { - Ecore_List2 *l; - double t1 = 0.; - double t2 = 0.; + int rend = 0; - if (_ecore_evas_fps_debug) + if (ee->visible) { - t1 = ecore_time_get(); - } - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - if (ee->visible) - { - Evas_List *updates; - -#ifdef BUILD_ECORE_EVAS_BUFFER - Evas_List *ll; -#endif - - if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); -#ifdef BUILD_ECORE_EVAS_BUFFER - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) - { - Ecore_Evas *ee2; - - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); - } -#endif - 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); - } - else - evas_norender(ee->evas); + 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); } - if (_ecore_evas_fps_debug) - { - t2 = ecore_time_get(); - _ecore_evas_fps_debug_rendertime_add(t2 - t1); - } - return 1; + else + evas_norender(ee->evas); + return rend; } static int -_ecore_evas_fb_init(int w, int h) +_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; - int keyboard_handled = 0; - - DIR *input_dir; - struct dirent *input_entry; - + _ecore_evas_init_count++; if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - - if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; - ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL); - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); + + ecore_event_evas_init(); + /* register all input devices */ - input_dir = opendir("/dev/input/"); - if (!input_dir) return _ecore_evas_init_count; - - ecore_evas_input_devices = ecore_list_new(); - while ((input_entry = readdir(input_dir))) + ls = eina_file_direct_ls("/dev/input/"); + + EINA_ITERATOR_FOREACH(ls, info) { - char device_path[256]; - - if (strncmp(input_entry->d_name, "event", 5) != 0) - continue; - - snprintf(device_path, 256, "/dev/input/%s", input_entry->d_name); - if (!(device = ecore_fb_input_device_open(device_path))) - continue; - - caps = ecore_fb_input_device_cap_get(device); - - if (ecore_evas_input_devices) - { - /* Mouse */ - if (caps & ECORE_FB_INPUT_DEVICE_CAP_RELATIVE) - { - ecore_fb_input_device_axis_size_set(device, w, h); - ecore_fb_input_device_listen(device,1); - ecore_list_append(ecore_evas_input_devices, device); - if (!mouse_handled) - { - ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL); - ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_FB_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_list_append(ecore_evas_input_devices, device); - if (!keyboard_handled) - { - ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_FB_EVENT_KEY_DOWN, _ecore_evas_event_key_down, NULL); - ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_FB_EVENT_KEY_UP, _ecore_evas_event_key_up, NULL); - keyboard_handled = 1; - } - } - } + 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_evas_event_handlers[2] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_event_mouse_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_BUTTON_UP, _ecore_evas_event_mouse_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_FB_EVENT_MOUSE_MOVE, _ecore_evas_event_mouse_move, NULL); - mouse_handled = 1; - } + 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; } @@ -331,7 +255,8 @@ _ecore_evas_fb_init(int w, int h) static void _ecore_evas_fb_free(Ecore_Evas *ee) { - ecore_evases = _ecore_list2_remove(ecore_evases, ee); + ecore_evas_input_event_unregister(ee); + if (fb_ee == ee) fb_ee = NULL; _ecore_evas_fb_shutdown(); ecore_fb_shutdown(); } @@ -339,6 +264,8 @@ _ecore_evas_fb_free(Ecore_Evas *ee) 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; @@ -354,12 +281,14 @@ _ecore_evas_resize(Ecore_Evas *ee, int w, int 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); + 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; @@ -375,15 +304,15 @@ _ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int 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); + if (ee->func.fn_resize) ee->func.fn_resize(ee); } static void -_ecore_evas_rotation_set(Ecore_Evas *ee, int rotation) +_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; @@ -391,60 +320,98 @@ _ecore_evas_rotation_set(Ecore_Evas *ee, int rotation) if (rot_dif < 0) rot_dif = -rot_dif; if (rot_dif != 180) { - - einfo->info.rotation = rotation; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - if (!ee->prop.fullscreen) - { - int tmp; - - tmp = ee->w; - ee->w = ee->h; - ee->h = tmp; - } - 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; + + 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - ee->rotation = rotation; + 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(ee, ee->mouse.x, ee->mouse.y, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff)); + _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 == NULL) + 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 = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; } ee->prop.cursor.object = obj; @@ -453,88 +420,90 @@ _ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int h 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_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; - 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); + 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; - 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.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 (ecore_evas_input_devices) - { - Ecore_Fb_Input_Device *dev; - - ecore_list_first_goto(ecore_evas_input_devices); - while ((dev = ecore_list_next(ecore_evas_input_devices))) - ecore_fb_input_device_axis_size_set(dev, ee->w, ee->h); - } if (resized) { - if (ee->func.fn_resize) ee->func.fn_resize(ee); + 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; - - while (ecore_evases) _ecore_evas_free(ecore_evases); - for (i = 0; i < 5; i++) - ecore_event_handler_del(ecore_evas_event_handlers[i]); - ecore_idle_enterer_del(ecore_evas_idle_enterer); - ecore_evas_idle_enterer = NULL; - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); - ecore_fb_ts_shutdown(); + 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 const Ecore_Evas_Engine_Func _ecore_fb_engine_func = +static Ecore_Evas_Engine_Func _ecore_fb_engine_func = { _ecore_evas_fb_free, NULL, @@ -557,8 +526,8 @@ static const Ecore_Evas_Engine_Func _ecore_fb_engine_func = _ecore_evas_move_resize, _ecore_evas_rotation_set, NULL, - NULL, - NULL, + _ecore_evas_show, + _ecore_evas_hide, NULL, NULL, NULL, @@ -579,19 +548,36 @@ static const Ecore_Evas_Engine_Func _ecore_fb_engine_func = 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 }; #endif /** - * To be documented. - * - * FIXME: To be fixed. + * @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(char *disp_name, int rotation, int w, int h) +ecore_evas_fb_new(const char *disp_name, int rotation, int w, int h) { -#ifdef BUILD_ECORE_EVAS_FB Evas_Engine_Info_FB *einfo; Ecore_Evas *ee; @@ -602,7 +588,7 @@ ecore_evas_fb_new(char *disp_name, int rotation, int w, int h) 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); @@ -610,11 +596,11 @@ ecore_evas_fb_new(char *disp_name, int rotation, int w, int h) if (!ee) return NULL; ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); - - _ecore_evas_fb_init(w, h); - + + _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); @@ -624,18 +610,20 @@ ecore_evas_fb_new(char *disp_name, int rotation, int w, int h) 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.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); @@ -653,32 +641,38 @@ ecore_evas_fb_new(char *disp_name, int rotation, int w, int h) } einfo = (Evas_Engine_Info_FB *)evas_engine_info_get(ee->evas); - if (einfo) + if (einfo && disp_name) { - einfo->info.virtual_terminal = 0; - einfo->info.device_number = strtol(disp_name, NULL, 10); - einfo->info.device_number = 0; - einfo->info.refresh = 0; - einfo->info.rotation = ee->rotation; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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; + } } - 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, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), 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); - ecore_evases = _ecore_list2_prepend(ecore_evases, 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 - disp_name = NULL; - rotation = w = h = 0; +EAPI Ecore_Evas * +ecore_evas_fb_new(const char *disp_name __UNUSED__, int rotation __UNUSED__, int w __UNUSED__, int h __UNUSED__) +{ return NULL; -#endif } +#endif diff --git a/src/lib/ecore_evas/ecore_evas_private.h b/src/lib/ecore_evas/ecore_evas_private.h index 2fd475a..664748c 100644 --- a/src/lib/ecore_evas/ecore_evas_private.h +++ b/src/lib/ecore_evas/ecore_evas_private.h @@ -1,62 +1,42 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ #ifndef _ECORE_EVAS_PRIVATE_H #define _ECORE_EVAS_PRIVATE_H -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "Ecore_Data.h" - -#include -#include -#include - -#ifdef HAVE_SYS_MMAN_H -# include -#endif - #include +#include +#include +#include +#include #define ECORE_MAGIC_EVAS 0x76543211 -#ifndef BUILD_ECORE_DIRECTFB -# undef BUILD_ECORE_EVAS_DIRECTFB -#endif - #ifdef BUILD_ECORE_EVAS_X11 -# include "Ecore_X.h" +# include +# include # ifdef HAVE_ECORE_X_XCB # include -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB -# include -# endif -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB -# include -# include -# endif # endif # ifdef HAVE_ECORE_X_XLIB # include # include -# ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 -# include -# endif -# ifdef BUILD_ECORE_EVAS_XRENDER_X11 -# include -# include -# endif -# ifdef BUILD_ECORE_EVAS_OPENGL_X11 -# include -# endif -# ifdef BUILD_ECORE_EVAS_SOFTWARE_16_X11 -# include -# endif # 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 @@ -66,12 +46,15 @@ # include "Ecore_DirectFB.h" #endif -#ifdef BUILD_ECORE_EVAS_BUFFER +#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 @@ -91,84 +74,154 @@ # include #endif +#ifdef BUILD_ECORE_EVAS_GL_COCOA +# include "Ecore_Cocoa.h" +# include +#endif + +#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL) +# include "Ecore_Wayland.h" +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +# include +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +# 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 Ecore_Evas; -typedef struct _Ecore_Evas_Engine Ecore_Evas_Engine; +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, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_move_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_show_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_hide_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_delete_request_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_destroy_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_focus_in_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_focus_out_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_mouse_in_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_mouse_out_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_sticky_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_unsticky_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_pre_render_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - void (*fn_callback_post_render_set) (Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)); - 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); - 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_window_get) (Ecore_Evas *ee); + 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; -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) - struct { +/* TODO: UGLY! This should be an union or inheritance! */ +#ifdef BUILD_ECORE_EVAS_X11 + struct + { Ecore_X_Window win_root; - Ecore_X_Window win; - Evas_List *win_extra; + Eina_List *win_extra; Ecore_X_Pixmap pmap; Ecore_X_Pixmap mask; Ecore_X_GC gc; -#ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB -# warning [XCB] No Region code -#else - Region damages; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ + 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; @@ -181,6 +234,7 @@ struct _Ecore_Evas_Engine unsigned char above : 1; unsigned char below : 1; } state; + Ecore_X_Window win_shaped_input; } x; #endif #ifdef BUILD_ECORE_EVAS_FB @@ -189,10 +243,13 @@ struct _Ecore_Evas_Engine int real_h; } fb; #endif -#ifdef BUILD_ECORE_EVAS_BUFFER +#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 @@ -203,39 +260,69 @@ struct _Ecore_Evas_Engine #ifdef BUILD_ECORE_EVAS_WIN32 struct { Ecore_Win32_Window *parent; - Ecore_Win32_Window *window; - struct { - unsigned char fullscreen : 1; - } state; + 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 { - Ecore_List __list_data; + EINA_INLIST; ECORE_MAGIC; Evas *evas; const char *driver; char *name; int x, y, w, h; short rotation; - char shaped : 1; - char visible : 1; - char draw_ok : 1; - char should_be_visible : 1; - char alpha : 1; + 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; - Evas_Hash *data; + Eina_Hash *data; struct { + int x, y, w, h; + } req; + + struct { int x, y; } mouse; @@ -247,6 +334,7 @@ struct _Ecore_Evas char *title; char *name; char *clas; + char *profile; struct { int w, h; } min, @@ -261,7 +349,11 @@ struct _Ecore_Evas } 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; @@ -271,7 +363,13 @@ struct _Ecore_Evas char withdrawn : 1; char sticky : 1; char request_pos : 1; - } prop; + 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); @@ -288,23 +386,36 @@ struct _Ecore_Evas 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; - Evas_List *sub_ecore_evas; + 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_BUFFER +#ifdef BUILD_ECORE_EVAS_SOFTWARE_BUFFER int _ecore_evas_buffer_shutdown(void); -void _ecore_evas_buffer_render(Ecore_Evas *ee); +int _ecore_evas_buffer_render(Ecore_Evas *ee); #endif #ifdef BUILD_ECORE_EVAS_DIRECTFB int _ecore_evas_directfb_shutdown(void); @@ -315,11 +426,91 @@ int _ecore_evas_win32_shutdown(void); #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 + +#if defined(BUILD_ECORE_EVAS_WAYLAND_SHM) || defined(BUILD_ECORE_EVAS_WAYLAND_EGL) +int _ecore_evas_wl_common_init(void); +int _ecore_evas_wl_common_shutdown(void); +void _ecore_evas_wl_common_pre_free(Ecore_Evas *ee); +void _ecore_evas_wl_common_free(Ecore_Evas *ee); +void _ecore_evas_wl_common_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)); +void _ecore_evas_wl_common_move(Ecore_Evas *ee, int x, int y); +void _ecore_evas_wl_common_raise(Ecore_Evas *ee); +void _ecore_evas_wl_common_title_set(Ecore_Evas *ee, const char *title); +void _ecore_evas_wl_common_name_class_set(Ecore_Evas *ee, const char *n, const char *c); +void _ecore_evas_wl_common_size_min_set(Ecore_Evas *ee, int w, int h); +void _ecore_evas_wl_common_size_max_set(Ecore_Evas *ee, int w, int h); +void _ecore_evas_wl_common_size_base_set(Ecore_Evas *ee, int w, int h); +void _ecore_evas_wl_common_size_step_set(Ecore_Evas *ee, int w, int h); +void _ecore_evas_wl_common_layer_set(Ecore_Evas *ee, int layer); +void _ecore_evas_wl_common_iconified_set(Ecore_Evas *ee, int iconify); +void _ecore_evas_wl_common_maximized_set(Ecore_Evas *ee, int max); +void _ecore_evas_wl_common_fullscreen_set(Ecore_Evas *ee, int full); +void _ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore); +int _ecore_evas_wl_common_pre_render(Ecore_Evas *ee); +int _ecore_evas_wl_common_render_updates(Ecore_Evas *ee); +void _ecore_evas_wl_common_post_render(Ecore_Evas *ee); +int _ecore_evas_wl_common_render(Ecore_Evas *ee); +void _ecore_evas_wl_common_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h); +void _ecore_evas_wl_common_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi); + +Evas_Object * _ecore_evas_wl_common_frame_add(Evas *evas); + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +void _ecore_evas_wayland_shm_resize(Ecore_Evas *ee, int location); +#endif + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +void _ecore_evas_wayland_egl_resize(Ecore_Evas *ee, int location); +#endif +#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 index 946f18e..da1ddbd 100644 --- a/src/lib/ecore_evas/ecore_evas_sdl.c +++ b/src/lib/ecore_evas/ecore_evas_sdl.c @@ -1,201 +1,148 @@ -#include "config.h" -#include "Ecore.h" -#include "ecore_private.h" +#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" -#ifdef BUILD_ECORE_EVAS_SDL -#include "Ecore_Sdl.h" -#include "Evas_Engine_SDL.h" -#endif -#ifdef BUILD_ECORE_EVAS_SDL +/* + * 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; -#ifndef _WIN32 -static int _ecore_evas_fps_debug = 0; -#endif /* _WIN32 */ -static Ecore_Evas *ecore_evases = NULL; -static Ecore_Event_Handler *ecore_evas_event_handlers[10] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + +static Ecore_Evas *sdl_ee = 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_Idler *ecore_evas_event = NULL; static const char *ecore_evas_sdl_default = "EFL SDL"; - -static 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); - evas_object_move(ee->prop.cursor.object, - x - ee->prop.cursor.hot.x, - y - ee->prop.cursor.hot.y); - } - evas_event_feed_mouse_move(ee->evas, x, y, timestamp, NULL); -} +static int _ecore_evas_fps_debug = 0; +static Ecore_Poller *ecore_evas_event; static Ecore_Evas * _ecore_evas_sdl_match(void) { - return ecore_evases; -} - -static int -_ecore_evas_sdl_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Sdl_Event_Key_Down *e; - Ecore_Evas *ee; - - e = event; - ee = _ecore_evas_sdl_match(); - - if (!ee) return 1; - /* pass on event */ - evas_event_feed_key_down(ee->evas, e->keyname, NULL, e->keycompose, NULL, e->time, NULL); - - return 0; /* dont pass it on */ -} - -static int -_ecore_evas_sdl_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Sdl_Event_Key_Up *e; - Ecore_Evas *ee; - - e = event; - ee = _ecore_evas_sdl_match(); - - if (!ee) return 1; - /* pass on event */ - evas_event_feed_key_up(ee->evas, e->keyname, NULL, e->keycompose, NULL, e->time, NULL); - - return 0; -} - -static int -_ecore_evas_sdl_event_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Sdl_Event_Mouse_Move *e; - Ecore_Evas *ee; - - e = event; - ee = _ecore_evas_sdl_match(); - - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); - - return 0; -} - -static int -_ecore_evas_sdl_event_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Sdl_Event_Mouse_Button_Down *e; - Ecore_Evas *ee; - Evas_Button_Flags flags; - - e = event; - ee = _ecore_evas_sdl_match(); - flags = EVAS_BUTTON_NONE; - - if (!ee) return 1; - /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_down(ee->evas, e->button, flags, e->time, NULL); - - return 0; -} - -static int -_ecore_evas_sdl_event_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Sdl_Event_Mouse_Button_Up *e; - Ecore_Evas *ee; - Evas_Button_Flags flags; - - e = event; - ee = _ecore_evas_sdl_match(); - flags = EVAS_BUTTON_NONE; - - if (!ee) return 1; - /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL); - - return 0; + return sdl_ee; } -static int -_ecore_evas_sdl_event_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) +static void * +_ecore_evas_sdl_switch_buffer(void *data, void *dest __UNUSED__) { - Ecore_Sdl_Event_Mouse_Wheel *e; - Ecore_Evas *ee; - - e = event; - ee = _ecore_evas_sdl_match(); - - if (!ee) return 1; /* pass on event */ - _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); - evas_event_feed_mouse_wheel(ee->evas, e->direction, e->wheel, e->time, NULL); - - return 0; + SDL_Flip(data); + return ((SDL_Surface*)data)->pixels; } -static int -_ecore_evas_sdl_event_got_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +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 1; + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ ee->prop.focused = 1; - - return 0; + 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_sdl_event_lost_focus(void *data __UNUSED__, int type __UNUSED__, void *event) +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 1; + if (!ee) return ECORE_CALLBACK_PASS_ON; /* pass on event */ ee->prop.focused = 0; - - return 0; + evas_focus_out(ee->evas); + if (ee->func.fn_focus_out) ee->func.fn_focus_out(ee); + return ECORE_CALLBACK_PASS_ON; } -static int +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 1; /* pass on event */ + 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 0; + return ECORE_CALLBACK_PASS_ON; } -static int +static Eina_Bool _ecore_evas_sdl_event_video_expose(void *data __UNUSED__, int type __UNUSED__, void *event __UNUSED__) { Ecore_Evas *ee; @@ -204,68 +151,65 @@ _ecore_evas_sdl_event_video_expose(void *data __UNUSED__, int type __UNUSED__, v ee = _ecore_evas_sdl_match(); - if (!ee) return 1; + 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 0; + return ECORE_CALLBACK_PASS_ON; } static int -_ecore_evas_idle_enter(void *data __UNUSED__) +_ecore_evas_render(Ecore_Evas *ee) { - Ecore_List2 *l; - double t1 = 0.; - double t2 = 0.; + Eina_List *updates; -#ifndef _WIN32 - if (_ecore_evas_fps_debug) + updates = evas_render_updates(ee->evas); + if (updates) { - t1 = ecore_time_get(); + evas_render_updates_free(updates); + _ecore_evas_idle_timeout_update(ee); } -#endif /* _WIN32 */ - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - if (ee->visible) - { - Evas_List *updates; - - 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); - } - else - evas_norender(ee->evas); - } -#ifndef _WIN32 - if (_ecore_evas_fps_debug) + 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) { - t2 = ecore_time_get(); - _ecore_evas_fps_debug_rendertime_add(t2 - t1); + 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); } -#endif /* _WIN32 */ - return 1; + + 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 int -_ecore_evas_sdl_event(void *data) +static Eina_Bool +_ecore_evas_sdl_event(void *data __UNUSED__) { ecore_sdl_feed_events(); - - return 1; + return ECORE_CALLBACK_RENEW; } static int -_ecore_evas_sdl_init(int w, int h) +_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; @@ -273,22 +217,22 @@ _ecore_evas_sdl_init(int w, int h) #ifndef _WIN32 if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; #endif /* _WIN32 */ - ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL); - ecore_evas_event = ecore_timer_add(0.008, _ecore_evas_sdl_event, NULL); + // 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_evas_event_handlers[0] = ecore_event_handler_add(ECORE_SDL_EVENT_KEY_DOWN, _ecore_evas_sdl_event_key_down, NULL); - ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_SDL_EVENT_KEY_UP, _ecore_evas_sdl_event_key_up, NULL); - ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_SDL_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_sdl_event_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_SDL_EVENT_MOUSE_BUTTON_UP, _ecore_evas_sdl_event_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_SDL_EVENT_MOUSE_MOVE, _ecore_evas_sdl_event_mouse_move, NULL); - ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_SDL_EVENT_MOUSE_WHEEL, _ecore_evas_sdl_event_mouse_wheel, NULL); - ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_SDL_EVENT_GOT_FOCUS, _ecore_evas_sdl_event_got_focus, NULL); - ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_SDL_EVENT_LOST_FOCUS, _ecore_evas_sdl_event_lost_focus, NULL); - ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_SDL_EVENT_RESIZE, _ecore_evas_sdl_event_video_resize, NULL); - ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_SDL_EVENT_EXPOSE, _ecore_evas_sdl_event_video_expose, NULL); + 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; } @@ -299,17 +243,15 @@ _ecore_evas_sdl_shutdown(void) _ecore_evas_init_count--; if (_ecore_evas_init_count == 0) { - int i; + unsigned 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_idle_enterer_del(ecore_evas_idle_enterer); - ecore_evas_idle_enterer = NULL; - ecore_timer_del(ecore_evas_event); + 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(); + if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); #endif /* _WIN32 */ } if (_ecore_evas_init_count < 0) _ecore_evas_init_count = 0; @@ -319,7 +261,9 @@ _ecore_evas_sdl_shutdown(void) static void _ecore_evas_sdl_free(Ecore_Evas *ee) { - ecore_evases = _ecore_list2_remove(ecore_evases, ee); + if (sdl_ee == ee) sdl_ee = NULL; + + ecore_event_window_unregister(0); _ecore_evas_sdl_shutdown(); ecore_sdl_shutdown(); } @@ -327,10 +271,48 @@ _ecore_evas_sdl_free(Ecore_Evas *ee) 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); @@ -353,19 +335,36 @@ _ecore_evas_move_resize(Ecore_Evas *ee, int x __UNUSED__, int y __UNUSED__, int } 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 == NULL) + 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 = NULL; + ee->prop.cursor.layer = 0; + ee->prop.cursor.hot.x = 0; + ee->prop.cursor.hot.y = 0; + return; } ee->prop.cursor.object = obj; @@ -375,14 +374,16 @@ _ecore_evas_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int h 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); + 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 const Ecore_Evas_Engine_Func _ecore_sdl_engine_func = +static Ecore_Evas_Engine_Func _ecore_sdl_engine_func = { _ecore_evas_sdl_free, NULL, @@ -405,7 +406,7 @@ static const Ecore_Evas_Engine_Func _ecore_sdl_engine_func = _ecore_evas_move_resize, NULL, NULL, - NULL, + _ecore_evas_show, NULL, NULL, NULL, @@ -427,33 +428,36 @@ static const Ecore_Evas_Engine_Func _ecore_sdl_engine_func = 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 }; -#endif -EAPI Ecore_Evas* -ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface, int noframe, int alpha) +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) { -#ifdef BUILD_ECORE_EVAS_SDL - Evas_Engine_Info_SDL *einfo; Ecore_Evas *ee; - int rmethod; if (!name) name = ecore_evas_sdl_default; - rmethod = evas_render_method_lookup("software_sdl"); - if (!rmethod) return NULL; - - if (!ecore_sdl_init(name)) return NULL; - ee = calloc(1, sizeof(Ecore_Evas)); if (!ee) return NULL; ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); - _ecore_evas_sdl_init(w, h); - ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_sdl_engine_func; ee->driver = "sdl"; @@ -475,6 +479,9 @@ ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface 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(); @@ -484,31 +491,167 @@ ecore_evas_sdl_new(const char* name, int w, int h, int fullscreen, int hwsurface evas_output_size_set(ee->evas, w, h); evas_output_viewport_set(ee->evas, 0, 0, w, h); - einfo = (Evas_Engine_Info_SDL*) evas_engine_info_get(ee->evas); - if (einfo) + if (rmethod == evas_render_method_lookup("buffer")) { - einfo->info.fullscreen = fullscreen; - einfo->info.hwsurface = hwsurface; - einfo->info.noframe = noframe; - einfo->info.alpha = alpha; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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; } - 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, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), 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; - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); + ee = _ecore_evas_internal_sdl_new(rmethod, name, w, h, fullscreen, hwsurface, noframe, alpha); return ee; +} #else - fprintf(stderr, "OUTCH !\n"); +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..a860969 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_util.c @@ -0,0 +1,451 @@ +#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; + + if (!storage) + { + ERR("Storage is missing"); + return 0; + } + + 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_common.c b/src/lib/ecore_evas/ecore_evas_wayland_common.c new file mode 100644 index 0000000..257fd6e --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wayland_common.c @@ -0,0 +1,657 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ecore_evas_private.h" +#include "Ecore_Evas.h" + +/* 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; +}; + +static Evas_Smart *_ecore_evas_wl_common_smart = NULL; + +/* local variables */ + +static int _ecore_evas_wl_init_count = 0; +static Ecore_Event_Handler *_ecore_evas_wl_event_hdls[5]; + +static Eina_Bool +_ecore_evas_wl_common_cb_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_In *ev; + + 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); + ee->in = EINA_TRUE; + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_ecore_evas_wl_common_cb_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Mouse_Out *ev; + + 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); + 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_common_cb_focus_in(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + 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_common_cb_focus_out(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Evas *ee; + Ecore_Wl_Event_Focus_In *ev; + + 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_common_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; + + 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_common_move(ee, ev->x, ev->y); + ee->engine.func->fn_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; +} + +int +_ecore_evas_wl_common_init(void) +{ + 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_common_cb_mouse_in, NULL); + _ecore_evas_wl_event_hdls[1] = + ecore_event_handler_add(ECORE_WL_EVENT_MOUSE_OUT, + _ecore_evas_wl_common_cb_mouse_out, NULL); + _ecore_evas_wl_event_hdls[2] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_IN, + _ecore_evas_wl_common_cb_focus_in, NULL); + _ecore_evas_wl_event_hdls[3] = + ecore_event_handler_add(ECORE_WL_EVENT_FOCUS_OUT, + _ecore_evas_wl_common_cb_focus_out, NULL); + _ecore_evas_wl_event_hdls[4] = + ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_CONFIGURE, + _ecore_evas_wl_common_cb_window_configure, NULL); + + ecore_event_evas_init(); + + return _ecore_evas_wl_init_count; +} + +int +_ecore_evas_wl_common_shutdown(void) +{ + unsigned int i = 0; + + 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; +} + +void +_ecore_evas_wl_common_pre_free(Ecore_Evas *ee) +{ + if (!ee) return; + if (ee->engine.wl.frame) evas_object_del(ee->engine.wl.frame); +} + +void +_ecore_evas_wl_common_free(Ecore_Evas *ee) +{ + 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_common_shutdown(); + ecore_wl_shutdown(); +} + +void +_ecore_evas_wl_common_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 (!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); + } +} + +void +_ecore_evas_wl_common_callback_resize_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_resize = func; +} + +void +_ecore_evas_wl_common_callback_move_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_move = func; +} + +void +_ecore_evas_wl_common_callback_delete_request_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_delete_request = func; +} + +void +_ecore_evas_wl_common_callback_focus_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_focus_in = func; +} + +void +_ecore_evas_wl_common_callback_focus_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_focus_out = func; +} + +void +_ecore_evas_wl_common_callback_mouse_in_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_mouse_in = func; +} + +void +_ecore_evas_wl_common_callback_mouse_out_set(Ecore_Evas *ee, void (*func)(Ecore_Evas *ee)) +{ + if (!ee) return; + ee->func.fn_mouse_out = func; +} + +void +_ecore_evas_wl_common_move(Ecore_Evas *ee, int x, int y) +{ + 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_common_smart_add(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + Evas *evas; + + 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_common_smart_del(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + 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_common_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + EE_Wl_Smart_Data *sd; + + 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_common_smart_show(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_show(sd->frame); + evas_object_show(sd->text); +} + +static void +_ecore_evas_wl_common_smart_hide(Evas_Object *obj) +{ + EE_Wl_Smart_Data *sd; + + if (!(sd = evas_object_smart_data_get(obj))) return; + evas_object_hide(sd->text); + evas_object_hide(sd->frame); +} + +static void +_ecore_evas_wl_common_smart_init(void) +{ + if (_ecore_evas_wl_common_smart) return; + { + static const Evas_Smart_Class sc = + { + "ecore_evas_wl_frame", EVAS_SMART_CLASS_VERSION, + _ecore_evas_wl_common_smart_add, + _ecore_evas_wl_common_smart_del, + NULL, + _ecore_evas_wl_common_smart_resize, + _ecore_evas_wl_common_smart_show, + _ecore_evas_wl_common_smart_hide, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL + }; + _ecore_evas_wl_common_smart = evas_smart_class_new(&sc); + } +} + +Evas_Object * +_ecore_evas_wl_common_frame_add(Evas *evas) +{ + _ecore_evas_wl_common_smart_init(); + return evas_object_smart_add(evas, _ecore_evas_wl_common_smart); +} + +void +_ecore_evas_wl_common_raise(Ecore_Evas *ee) +{ + if ((!ee) || (!ee->visible)) return; + ecore_wl_window_raise(ee->engine.wl.win); +} + +void +_ecore_evas_wl_common_title_set(Ecore_Evas *ee, const char *title) +{ + 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); +} + +void +_ecore_evas_wl_common_name_class_set(Ecore_Evas *ee, const char *n, const char *c) +{ + 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); +} + +void +_ecore_evas_wl_common_size_min_set(Ecore_Evas *ee, int w, int h) +{ + 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; +} + +void +_ecore_evas_wl_common_size_max_set(Ecore_Evas *ee, int w, int h) +{ + 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; +} + +void +_ecore_evas_wl_common_size_base_set(Ecore_Evas *ee, int w, int h) +{ + 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; +} + +void +_ecore_evas_wl_common_size_step_set(Ecore_Evas *ee, int w, int h) +{ + 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; +} + +void +_ecore_evas_wl_common_layer_set(Ecore_Evas *ee, int layer) +{ + if (!ee) return; + if (ee->prop.layer == layer) return; + if (layer < 1) layer = 1; + else if (layer > 255) layer = 255; + ee->prop.layer = layer; +} + +void +_ecore_evas_wl_common_iconified_set(Ecore_Evas *ee, int iconify) +{ + if (!ee) return; + if (ee->prop.iconified == iconify) return; + ee->prop.iconified = iconify; + /* FIXME: Implement this in Wayland someshow */ +} + +void +_ecore_evas_wl_common_maximized_set(Ecore_Evas *ee, int max) +{ + if (!ee) return; + if (ee->prop.maximized == max) return; + ee->prop.maximized = max; + ecore_wl_window_maximized_set(ee->engine.wl.win, max); +} + +void +_ecore_evas_wl_common_fullscreen_set(Ecore_Evas *ee, int full) +{ + if (!ee) return; + if (ee->prop.fullscreen == full) return; + ee->prop.fullscreen = full; + ecore_wl_window_fullscreen_set(ee->engine.wl.win, full); +} + +void +_ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore) +{ + if (!ee) return; + ee->ignore_events = ignore; + /* NB: Hmmm, may need to pass this to ecore_wl_window in the future */ +} + +int +_ecore_evas_wl_common_pre_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *ll = 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); + } + + return rend; +} + +int +_ecore_evas_wl_common_render_updates(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + + if ((updates = evas_render_updates(ee->evas))) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + 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); + rend = 1; + } + + return rend; +} + +void +_ecore_evas_wl_common_post_render(Ecore_Evas *ee) +{ + _ecore_evas_idle_timeout_update(ee); + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); +} + +int +_ecore_evas_wl_common_render(Ecore_Evas *ee) +{ + int rend = 0; + + if (!ee) return 0; + if (!ee->visible) + { + evas_norender(ee->evas); + return 0; + } + + rend = _ecore_evas_wl_common_pre_render(ee); + rend |= _ecore_evas_wl_common_render_updates(ee); + _ecore_evas_wl_common_post_render(ee); + + return rend; +} + +void +_ecore_evas_wl_common_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_wl_screen_size_get(w, h); +} + +void +_ecore_evas_wl_common_screen_dpi_get(const Ecore_Evas *ee __UNUSED__, int *xdpi, int *ydpi) +{ + int dpi = 0; + + 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; +} 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..545c295 --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wayland_egl.c @@ -0,0 +1,434 @@ +#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 "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_WAYLAND_EGL +# include "ecore_evas_private.h" +# include +# include + +/* local function prototypes */ +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_alpha_set(Ecore_Evas *ee, int alpha); +static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent); + +static Ecore_Evas_Engine_Func _ecore_wl_engine_func = +{ + _ecore_evas_wl_common_free, + _ecore_evas_wl_common_callback_resize_set, + _ecore_evas_wl_common_callback_move_set, + NULL, + NULL, + _ecore_evas_wl_common_callback_delete_request_set, + NULL, + _ecore_evas_wl_common_callback_focus_in_set, + _ecore_evas_wl_common_callback_focus_out_set, + _ecore_evas_wl_common_callback_mouse_in_set, + _ecore_evas_wl_common_callback_mouse_out_set, + NULL, // sticky_set + NULL, // unsticky_set + NULL, // pre_render_set + NULL, // post_render_set + _ecore_evas_wl_common_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_common_raise, + NULL, // lower + NULL, // activate + _ecore_evas_wl_common_title_set, + _ecore_evas_wl_common_name_class_set, + _ecore_evas_wl_common_size_min_set, + _ecore_evas_wl_common_size_max_set, + _ecore_evas_wl_common_size_base_set, + _ecore_evas_wl_common_size_step_set, + NULL, // object_cursor_set + _ecore_evas_wl_common_layer_set, + NULL, // focus set + _ecore_evas_wl_common_iconified_set, + NULL, // borderless set + NULL, // override set + _ecore_evas_wl_common_maximized_set, + _ecore_evas_wl_common_fullscreen_set, + NULL, // func avoid_damage set + NULL, // func withdrawn set + NULL, // func sticky set + _ecore_evas_wl_common_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_common_render, + _ecore_evas_wl_common_screen_geometry_get, + _ecore_evas_wl_common_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"); + goto ee_err; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_wl_common_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); + goto err; + } + } + else + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + goto err; + } + + ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_common_pre_free); + + if (ee->prop.draw_frame) + { + ee->engine.wl.frame = _ecore_evas_wl_common_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); + + return ee; + + err: + ecore_evas_free(ee); + _ecore_evas_wl_common_shutdown(); + + ee_err: + ecore_wl_shutdown(); + return NULL; +} + +static void +_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h) +{ + 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.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_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); + } +} + +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); + } +} +#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..d2bc08a --- /dev/null +++ b/src/lib/ecore_evas/ecore_evas_wayland_shm.c @@ -0,0 +1,657 @@ +#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 "Ecore_Evas.h" + +#ifdef BUILD_ECORE_EVAS_WAYLAND_SHM +# include "ecore_evas_private.h" +# include +# include + +/* local function prototypes */ +static void _ecore_evas_wl_free(Ecore_Evas *ee); +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_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); + +/* SHM Only */ +static void _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee); +static void _ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size); +static void _ecore_evas_wl_buffer_free(Ecore_Evas *ee); +static void _ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h); + +/* Frame listener */ +static void _ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time); +static const struct wl_callback_listener frame_listener = +{ + _ecore_evas_wl_frame_complete, +}; + +static Ecore_Evas_Engine_Func _ecore_wl_engine_func = +{ + _ecore_evas_wl_free, + _ecore_evas_wl_common_callback_resize_set, + _ecore_evas_wl_common_callback_move_set, + NULL, + NULL, + _ecore_evas_wl_common_callback_delete_request_set, + NULL, + _ecore_evas_wl_common_callback_focus_in_set, + _ecore_evas_wl_common_callback_focus_out_set, + _ecore_evas_wl_common_callback_mouse_in_set, + _ecore_evas_wl_common_callback_mouse_out_set, + NULL, // sticky_set + NULL, // unsticky_set + NULL, // pre_render_set + NULL, // post_render_set + _ecore_evas_wl_common_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_common_raise, + NULL, // lower + NULL, // activate + _ecore_evas_wl_common_title_set, + _ecore_evas_wl_common_name_class_set, + _ecore_evas_wl_common_size_min_set, + _ecore_evas_wl_common_size_max_set, + _ecore_evas_wl_common_size_base_set, + _ecore_evas_wl_common_size_step_set, + NULL, // object_cursor_set + _ecore_evas_wl_common_layer_set, + NULL, // focus set + _ecore_evas_wl_common_iconified_set, + NULL, // borderless set + NULL, // override set + _ecore_evas_wl_common_maximized_set, + _ecore_evas_wl_common_fullscreen_set, + NULL, // func avoid_damage set + NULL, // func withdrawn set + NULL, // func sticky set + _ecore_evas_wl_common_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_common_screen_geometry_get, + _ecore_evas_wl_common_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"); + goto ee_err; + } + + ECORE_MAGIC_SET(ee, ECORE_MAGIC_EVAS); + + _ecore_evas_wl_common_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.destination_alpha = ee->alpha; + einfo->info.rotation = ee->rotation; + if (!evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo)) + { + ERR("Failed to set Evas Engine Info for '%s'", ee->driver); + goto err; + } + } + else + { + ERR("Failed to get Evas Engine Info for '%s'", ee->driver); + goto err; + } + + ecore_evas_callback_pre_free_set(ee, _ecore_evas_wl_common_pre_free); + + if (ee->prop.draw_frame) + { + ee->engine.wl.frame = _ecore_evas_wl_common_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); + + return ee; + + err: + ecore_evas_free(ee); + _ecore_evas_wl_common_shutdown(); + + ee_err: + ecore_wl_shutdown(); + return NULL; +} + +static void +_ecore_evas_wl_free(Ecore_Evas *ee) +{ + _ecore_evas_wl_buffer_free(ee); + _ecore_evas_wl_shm_pool_free(ee); + _ecore_evas_wl_common_free(ee); +} + +static void +_ecore_evas_wl_resize(Ecore_Evas *ee, int w, int h) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + int fw = 0, fh = 0; + + 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); + + _ecore_evas_wl_buffer_new(ee, w, h); + + 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) + { + 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_common_move(ee, x, y); + if ((ee->w != w) || (ee->h != h)) + _ecore_evas_wl_resize(ee, w, h); +} + +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_buffer_new(ee, ee->w, ee->h); + + 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) + { + 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; + + _ecore_evas_wl_buffer_free(ee); + + 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); + } + + 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_alpha_set(Ecore_Evas *ee, int alpha) +{ + Evas_Engine_Info_Wayland_Shm *einfo; + Ecore_Wl_Window *win = NULL; + + 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); */ + + _ecore_evas_wl_buffer_new(ee, ee->w, ee->h); + + 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 (win) + { + ecore_wl_window_update_size(win, ee->w, ee->h); + ecore_wl_window_buffer_attach(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); + + _ecore_evas_wl_buffer_new(ee, ee->w, ee->h); + + 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 void +_ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time __UNUSED__) +{ + Ecore_Evas *ee = data; + Ecore_Wl_Window *win = NULL; + + if (!ee) return; + if (!(win = ee->engine.wl.win)) return; + + win->frame_callback = NULL; + win->frame_pending = EINA_FALSE; + wl_callback_destroy(callback); + + if (win->surface) + { + win->frame_callback = wl_surface_frame(win->surface); + wl_callback_add_listener(win->frame_callback, &frame_listener, ee); + } +} + +static int +_ecore_evas_wl_render(Ecore_Evas *ee) +{ + int rend = 0; + Ecore_Wl_Window *win = NULL; + + if (!ee) return 0; + if (!ee->visible) + { + evas_norender(ee->evas); + return 0; + } + + if (!(win = ee->engine.wl.win)) return 0; + + rend = _ecore_evas_wl_common_pre_render(ee); + if (!(win->frame_pending)) + { + /* FIXME - ideally have an evas_changed_get to return the value + * of evas->changed to avoid creating this callback and + * destroying it again + */ + + if (!win->frame_callback) + { + win->frame_callback = wl_surface_frame(win->surface); + wl_callback_add_listener(win->frame_callback, &frame_listener, ee); + } + + rend |= _ecore_evas_wl_common_render_updates(ee); + if (rend) + win->frame_pending = EINA_TRUE; + } + _ecore_evas_wl_common_post_render(ee); + return rend; +} + +static void +_ecore_evas_wl_shm_pool_free(Ecore_Evas *ee) +{ + if (!ee->engine.wl.pool) return; + + wl_shm_pool_destroy(ee->engine.wl.pool); + ee->engine.wl.pool = NULL; + ee->engine.wl.pool_size = 0; + ee->engine.wl.pool_data = NULL; +} + +static void +_ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size) +{ + struct wl_shm *shm; + void *data; + char tmp[PATH_MAX]; + int fd; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (size <= ee->engine.wl.pool_size) + return; + + size *= 1.5; + _ecore_evas_wl_shm_pool_free(ee); + + if (!(shm = ecore_wl_shm_get())) + { + ERR("ecore_wl_shm_get returned NULL"); + return; + } + + strcpy(tmp, "/tmp/ecore-evas-wayland_shm-XXXXXX"); + if ((fd = mkstemp(tmp)) < 0) + { + ERR("Could not create temporary file."); + return; + } + + if (ftruncate(fd, size) < 0) + { + ERR("Could not truncate temporary file."); + goto end; + } + + data = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0); + unlink(tmp); + + if (data == MAP_FAILED) + { + ERR("mmap of temporary file failed."); + goto end; + } + + ee->engine.wl.pool_size = size; + ee->engine.wl.pool_data = data; + ee->engine.wl.pool = wl_shm_create_pool(shm, fd, size); + + end: + close(fd); +} + +static void +_ecore_evas_wl_buffer_free(Ecore_Evas *ee) +{ + if (!ee->engine.wl.buffer) return; + + wl_buffer_destroy(ee->engine.wl.buffer); + ee->engine.wl.buffer = NULL; +} + +static void +_ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h) +{ + unsigned int format; + int stride = 0; + + stride = (w * sizeof(int)); + + _ecore_evas_wl_shm_pool_create(ee, stride * h); + + if ((ee->alpha) || (ee->transparent)) + format = WL_SHM_FORMAT_ARGB8888; + else + format = WL_SHM_FORMAT_XRGB8888; + + _ecore_evas_wl_buffer_free(ee); + ee->engine.wl.buffer = + wl_shm_pool_create_buffer(ee->engine.wl.pool, 0, w, 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); + } +} +#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 index b68c524..59d6ed8 100644 --- a/src/lib/ecore_evas/ecore_evas_win32.c +++ b/src/lib/ecore_evas/ecore_evas_win32.c @@ -1,89 +1,71 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif #include /* for NULL */ -#include "Ecore.h" +#include #include "ecore_private.h" #ifdef BUILD_ECORE_EVAS_WIN32 -# include "Ecore_Win32.h" -# include "ecore_win32_private.h" +# 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 14 +#define ECORE_EVAS_EVENT_COUNT 10 static int _ecore_evas_init_count = 0; -static int _ecore_evas_fps_debug = 0; static Ecore_Event_Handler *ecore_evas_event_handlers[ECORE_EVAS_EVENT_COUNT]; -static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; -static Ecore_Evas *ecore_evases = NULL; -static Evas_Hash *ecore_evases_hash = NULL; - -static int _ecore_evas_win32_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event); - -static int _ecore_evas_win32_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event); -static int _ecore_evas_win32_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_win32_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); -static int _ecore_evas_win32_event_mouse_button_up(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 int _ecore_evas_win32_event_mouse_wheel(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 int _ecore_evas_win32_event_mouse_move(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 int _ecore_evas_win32_event_mouse_in(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 int _ecore_evas_win32_event_mouse_out(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 int _ecore_evas_win32_event_window_damage(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 int _ecore_evas_win32_event_window_destroy(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 int _ecore_evas_win32_event_window_show(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 int _ecore_evas_win32_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void *event); - -static int _ecore_evas_win32_event_window_configure(void *data __UNUSED__, int type __UNUSED__, void *event); - -static int _ecore_evas_win32_event_window_delete_request(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 void +static int _ecore_evas_win32_render(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_BUFFER - Evas_List *ll; -#endif + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; -#ifdef BUILD_ECORE_EVAS_BUFFER - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) { - Ecore_Evas *ee2; - - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(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); } -#endif + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); if (ee->prop.avoid_damage) { - Evas_List *updates; - updates = evas_render_updates(ee->evas); if (updates) evas_render_updates_free(updates); } @@ -93,49 +75,20 @@ _ecore_evas_win32_render(Ecore_Evas *ee) { if (ee->shaped) { - Evas_List *updates; - updates = evas_render_updates(ee->evas); if (updates) evas_render_updates_free(updates); } else { - Evas_List *updates; - 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); -} - -static int -_ecore_evas_win32_idle_enter(void *data __UNUSED__) -{ - Ecore_List2 *l; - double t1 = 0.0; - double t2 = 0.0; - - if (_ecore_evas_fps_debug) - { - t1 = ecore_time_get(); - } - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - _ecore_evas_win32_render(ee); - } -/* ecore_x_flush(); */ - if (_ecore_evas_fps_debug) - { - t2 = ecore_time_get(); -/* _ecore_evas_fps_debug_rendertime_add(t2 - t1); */ - } - return 1; + return rend; } static int @@ -145,26 +98,18 @@ _ecore_evas_win32_init(void) if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - if (getenv("ECORE_EVAS_FPS_DEBUG")) - _ecore_evas_fps_debug = 1; - - ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_win32_idle_enter, NULL); - - ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_WIN32_EVENT_KEY_DOWN, _ecore_evas_win32_event_key_down, NULL); - ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_WIN32_EVENT_KEY_UP, _ecore_evas_win32_event_key_up, NULL); - ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_win32_event_mouse_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_BUTTON_UP, _ecore_evas_win32_event_mouse_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_WHEEL, _ecore_evas_win32_event_mouse_wheel, NULL); - ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_MOVE, _ecore_evas_win32_event_mouse_move, NULL); - ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_IN, _ecore_evas_win32_event_mouse_in, NULL); - ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_WIN32_EVENT_MOUSE_OUT, _ecore_evas_win32_event_mouse_out, NULL); - ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, _ecore_evas_win32_event_window_damage, NULL); - ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DESTROY, _ecore_evas_win32_event_window_destroy, NULL); - ecore_evas_event_handlers[10] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_SHOW, _ecore_evas_win32_event_window_show, NULL); - ecore_evas_event_handlers[11] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_HIDE, _ecore_evas_win32_event_window_hide, NULL); - ecore_evas_event_handlers[12] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, _ecore_evas_win32_event_window_configure, NULL); - ecore_evas_event_handlers[13] = ecore_event_handler_add(ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_win32_event_window_delete_request, NULL); - + 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; } @@ -174,13 +119,11 @@ _ecore_evas_win32_shutdown(void) _ecore_evas_init_count--; if (_ecore_evas_init_count == 0) { - int i; + int i; - while (ecore_evases) _ecore_evas_free(ecore_evases); - for (i = 0; i < ECORE_EVAS_EVENT_COUNT; i++) - ecore_event_handler_del(ecore_evas_event_handlers[i]); - ecore_idle_enterer_del(ecore_evas_idle_enterer); - ecore_evas_idle_enterer = NULL; + 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; @@ -188,235 +131,99 @@ _ecore_evas_win32_shutdown(void) return _ecore_evas_init_count; } -static char * -_ecore_evas_win32_winid_str_get(Ecore_Win32_Window *window) -{ - static char id[9]; - const char *vals = "qWeRtYuIoP5-$&<~"; - unsigned int val; - - val = (unsigned int)window; - 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_win32_match(Ecore_Win32_Window *window) -{ - Ecore_Evas *ee; - - ee = evas_hash_find(ecore_evases_hash, _ecore_evas_win32_winid_str_get(window)); - - return ee; -} - -static int -_ecore_evas_win32_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) +static Eina_Bool +_ecore_evas_win32_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_Win32_Event_Key_Down *e; - - e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - evas_event_feed_key_down(ee->evas, e->keyname, e->keysymbol, e->keycompose, NULL, e->time, NULL); - - return 1; -} + Ecore_Win32_Event_Mouse_In *e; -static int -_ecore_evas_win32_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Win32_Event_Key_Up *e; + INF("mouse in"); e = event; - ee = _ecore_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - evas_event_feed_key_up(ee->evas, e->keyname, e->keysymbol, e->keycompose, NULL, e->time, NULL); + if ((Ecore_Window)e->window != ee->prop.window) return 1; - return 1; -} - -static int -_ecore_evas_win32_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_Button_Down *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - - e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.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); */ - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_down(ee->evas, e->button, flags, e->time, NULL); - - printf (" * ee event button down %f %d %d\n", e->time, e->x, e->y); + 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 int -_ecore_evas_win32_event_mouse_button_up(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) { - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_Button_Up *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - - printf (" * ee event button up 0 \n"); - e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL); - - printf (" * ee event button up\n"); - - return 1; -} + Ecore_Evas *ee; + Ecore_Win32_Event_Mouse_Out *e; -static int -_ecore_evas_win32_event_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_Wheel *e; + INF("mouse out"); e = event; - ee = _ecore_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - evas_event_feed_mouse_wheel(ee->evas, e->direction, e->z, e->time, NULL); - - return 1; -} - -static void -_ecore_evas_win32_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); -} - -static int -_ecore_evas_win32_event_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_Move *e; + if ((Ecore_Window)e->window != ee->prop.window) return 1; - e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; /* FIXME to do */ /* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - _ecore_evas_win32_mouse_move_process(ee, e->x, e->y, e->time); + _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 int -_ecore_evas_win32_event_mouse_in(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) { - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_In *e; + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Focus_In *e; e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.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_win32_mouse_move_process(ee, e->x, e->y, e->time); - - return 1; + 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 int -_ecore_evas_win32_event_mouse_out(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) { - Ecore_Evas *ee; - Ecore_Win32_Event_Mouse_Out *e; + Ecore_Evas *ee; + Ecore_Win32_Event_Window_Focus_Out *e; e = event; - ee = _ecore_evas_win32_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; - - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - _ecore_evas_win32_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; + 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 int +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_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + if ((Ecore_Window)e->window != ee->prop.window) return 1; if (ee->prop.avoid_damage) { @@ -428,7 +235,6 @@ _ecore_evas_win32_event_window_damage(void *data __UNUSED__, int type __UNUSED__ } else { - printf (" * ee window event damage\n"); if (ee->rotation == 0) evas_damage_rectangle_add(ee->evas, e->x, @@ -458,34 +264,36 @@ _ecore_evas_win32_event_window_damage(void *data __UNUSED__, int type __UNUSED__ return 1; } -static int +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_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + if ((Ecore_Window)e->window != ee->prop.window) return 1; if (ee->func.fn_destroy) ee->func.fn_destroy(ee); ecore_evas_free(ee); - printf (" * ee event destroy\n"); return 1; } -static int +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; - printf (" * ee window event show\n"); + INF("window show"); + e = event; - ee = _ecore_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + 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); @@ -493,16 +301,18 @@ _ecore_evas_win32_event_window_show(void *data __UNUSED__, int type __UNUSED__, return 1; } -static int +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_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + 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); @@ -510,29 +320,39 @@ _ecore_evas_win32_event_window_hide(void *data __UNUSED__, int type __UNUSED__, return 1; } -static int +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_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + if ((Ecore_Window)e->window != ee->prop.window) return 1; - if ((ee->x != e->x) || (ee->y != e->y)) + if (ee->prop.override) { - ee->x = e->x; - ee->y = e->y; - if (ee->func.fn_move) ee->func.fn_move(ee); + 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)) { - printf (" * ee resize : 1\n"); 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); @@ -540,49 +360,50 @@ _ecore_evas_win32_event_window_configure(void *data __UNUSED__, int type __UNUSE } else { - printf (" * ee resize : 2\n"); 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, 1); + ecore_evas_avoid_damage_set(ee, pdam); } - /* FIXME: to do... */ -/* if (ee->shaped) */ -/* _ecore_evas_x_resize_shape(ee); */ +/* if (ee->shaped) */ +/* _ecore_evas_win32_region_border_resize(ee); */ if ((ee->expecting_resize.w > 0) && (ee->expecting_resize.h > 0)) { - printf (" * ee resize : 3\n"); if ((ee->expecting_resize.w == ee->w) && (ee->expecting_resize.h == ee->h)) - _ecore_evas_win32_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, - ecore_win32_current_time_get()); + _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; } - printf (" * ee resize : 4\n"); if (ee->func.fn_resize) ee->func.fn_resize(ee); } return 1; } -static int +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_evas_win32_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.win32.window) return 1; + if ((Ecore_Window)e->window != ee->prop.window) return 1; if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); - printf (" * ee event delete\n"); + INF(" * ee event delete\n"); return 1; } @@ -592,16 +413,17 @@ _ecore_evas_win32_event_window_delete_request(void *data __UNUSED__, int type __ static void _ecore_evas_win32_free(Ecore_Evas *ee) { - ecore_win32_window_del(ee->engine.win32.window); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_win32_winid_str_get(ee->engine.win32.window), ee); - ecore_evases = _ecore_list2_remove(ecore_evases, 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, - void (*func) (Ecore_Evas *ee)) + Ecore_Evas_Event_Cb func) { ee->func.fn_delete_request = func; } @@ -609,11 +431,16 @@ _ecore_evas_win32_callback_delete_request_set(Ecore_Evas *ee, 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(ee->engine.win32.window, x, y); + ecore_win32_window_move((struct _Ecore_Win32_Window *)ee->prop.window, + x, y); if (ee->func.fn_move) ee->func.fn_move(ee); } } @@ -621,12 +448,16 @@ _ecore_evas_win32_move(Ecore_Evas *ee, int x, int y) static void _ecore_evas_win32_resize(Ecore_Evas *ee, int width, int height) { - printf (" * _ecore_evas_win32_resize %d %d\n", width, 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(ee->engine.win32.window, width, 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); @@ -637,8 +468,16 @@ _ecore_evas_win32_resize(Ecore_Evas *ee, int width, int height) 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->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); } } @@ -646,7 +485,12 @@ _ecore_evas_win32_resize(Ecore_Evas *ee, int width, int height) static void _ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int height) { - printf (" * _ecore_evas_win32_resize\n"); + 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; @@ -659,7 +503,8 @@ _ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int heigh ee->y = y; ee->w = width; ee->h = height; - ecore_win32_window_move_resize(ee->engine.win32.window, x, y, width, 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); @@ -670,7 +515,16 @@ _ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int heigh 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->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); @@ -683,130 +537,202 @@ _ecore_evas_win32_move_resize(Ecore_Evas *ee, int x, int y, int width, int heigh } static void -_ecore_evas_win32_rotation_set(Ecore_Evas *ee, int rotation) +_ecore_evas_win32_rotation_set_internal(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")) + 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 - Evas_Engine_Info_Software_DDraw *einfo; - - einfo = (Evas_Engine_Info_Software_DDraw *)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_win32_window_resize(ee->engine.win32.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(ee->engine.win32.window, &w, &h); - ecore_win32_window_resize(ee->engine.win32.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_win32_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, - ecore_win32_current_time_get()); - } - else - { - einfo->info.rotation = rotation; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - ee->rotation = rotation; - _ecore_evas_win32_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); + 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) { - printf (" * ee window show\n"); + INF("ecore evas show"); + ee->should_be_visible = 1; if (ee->prop.avoid_damage) _ecore_evas_win32_render(ee); - ecore_win32_window_show(ee->engine.win32.window); + ecore_win32_window_show((struct _Ecore_Win32_Window *)ee->prop.window); /* if (ee->prop.fullscreen) */ -/* ecore_win32_window_focus(ee->engine.win32.window); */ +/* ecore_win32_window_focus(ee->prop.window); */ } static void _ecore_evas_win32_hide(Ecore_Evas *ee) { - ecore_win32_window_hide(ee->engine.win32.window); + 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(ee->engine.win32.window); + ecore_win32_window_raise((struct _Ecore_Win32_Window *)ee->prop.window); else - ecore_win32_window_raise(ee->engine.win32.window); + 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(ee->engine.win32.window); + ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window); else - ecore_win32_window_lower(ee->engine.win32.window); + ecore_win32_window_lower((struct _Ecore_Win32_Window *)ee->prop.window); } static void _ecore_evas_win32_activate(Ecore_Evas *ee) { - ecore_win32_window_focus_set(ee->engine.win32.window); + 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(ee->engine.win32.window, ee->prop.title); + ecore_win32_window_title_set((struct _Ecore_Win32_Window *)ee->prop.window, + ee->prop.title); } static void @@ -817,7 +743,8 @@ _ecore_evas_win32_size_min_set(Ecore_Evas *ee, int width, int height) 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(ee->engine.win32.window, width, height); + ecore_win32_window_size_min_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); } static void @@ -828,7 +755,8 @@ _ecore_evas_win32_size_max_set(Ecore_Evas *ee, int width, int height) 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(ee->engine.win32.window, width, height); + ecore_win32_window_size_max_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); } static void @@ -839,7 +767,8 @@ _ecore_evas_win32_size_base_set(Ecore_Evas *ee, int width, int height) 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(ee->engine.win32.window, width, height); + ecore_win32_window_size_base_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); } static void @@ -850,7 +779,8 @@ _ecore_evas_win32_size_step_set(Ecore_Evas *ee, int width, int height) 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(ee->engine.win32.window, width, height); + ecore_win32_window_size_step_set((struct _Ecore_Win32_Window *)ee->prop.window, + width, height); } static void @@ -863,12 +793,12 @@ _ecore_evas_win32_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho 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->engine.win32.window, 1); - return; + 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; @@ -876,13 +806,13 @@ _ecore_evas_win32_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho ee->prop.cursor.hot.x = hot_x; ee->prop.cursor.hot.y = hot_y; - ecore_win32_window_cursor_show(ee->engine.win32.window, 0); + 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); + 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); @@ -892,7 +822,7 @@ _ecore_evas_win32_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho static void _ecore_evas_win32_focus_set(Ecore_Evas *ee, int on __UNUSED__) { - ecore_win32_window_focus_set(ee->engine.win32.window); + ecore_win32_window_focus((struct _Ecore_Win32_Window *)ee->prop.window); } static void @@ -901,7 +831,8 @@ _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(ee->engine.win32.window, ee->prop.iconified); + ecore_win32_window_iconified_set((struct _Ecore_Win32_Window *)ee->prop.window, + ee->prop.iconified); } static void @@ -910,39 +841,228 @@ _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(ee->engine.win32.window, ee->prop.borderless); + 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) { - if ((ee->prop.fullscreen && on) || - (!ee->prop.fullscreen && !on)) return; + 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; - ecore_win32_window_fullscreen_set(ee->engine.win32.window, ee->prop.borderless); - /* FIXME: what to do with that code ?? */ -/* if (ee->should_be_visible) */ -/* ecore_x_netwm_state_request_send(ee->engine.x.win, ee->engine.x.win_root, */ -/* ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on); */ -/* else */ -/* _ecore_evas_win32_state_update(ee); */ + 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; -#endif /* BUILD_ECORE_EVAS_WIN32 */ + 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_window_get(Ecore_Evas *ee) +static void +_ecore_evas_win32_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) { -#ifdef BUILD_ECORE_EVAS_WIN32 - return ee->engine.win32.window; -#else - return NULL; -#endif /* BUILD_ECORE_EVAS_WIN32 */ + 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); } -#ifdef BUILD_ECORE_EVAS_WIN32 -static const Ecore_Evas_Engine_Func _ecore_win32_engine_func = +static Ecore_Evas_Engine_Func _ecore_win32_engine_func = { _ecore_evas_win32_free, NULL, @@ -964,7 +1084,7 @@ static const Ecore_Evas_Engine_Func _ecore_win32_engine_func = _ecore_evas_win32_resize, _ecore_evas_win32_move_resize, _ecore_evas_win32_rotation_set, - NULL, /* _ecore_evas_x_shaped_set */ + _ecore_evas_win32_shaped_set, _ecore_evas_win32_show, _ecore_evas_win32_hide, _ecore_evas_win32_raise, @@ -981,25 +1101,80 @@ static const Ecore_Evas_Engine_Func _ecore_win32_engine_func = _ecore_evas_win32_focus_set, _ecore_evas_win32_iconified_set, _ecore_evas_win32_borderless_set, - NULL, /* _ecore_evas_x_override_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 */ - NULL, /* _ecore_evas_x_alpha_set */ - _ecore_evas_win32_window_get + _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_ddraw_init(Ecore_Evas *ee) +_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; @@ -1017,22 +1192,29 @@ _ecore_evas_engine_software_ddraw_init(Ecore_Evas *ee) if (einfo) { /* FIXME: REDRAW_DEBUG missing for now */ - einfo->info.window = ((struct _Ecore_Win32_Window *)ee->engine.win32.window)->window; + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; einfo->info.depth = ecore_win32_screen_depth_get(); einfo->info.rotation = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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; -#else - return 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ } +#endif /* BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ +#ifdef BUILD_ECORE_EVAS_DIRECT3D static int _ecore_evas_engine_direct3d_init(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_DIRECT3D Evas_Engine_Info_Direct3D *einfo; const char *driver; int rmethod; @@ -1050,22 +1232,29 @@ _ecore_evas_engine_direct3d_init(Ecore_Evas *ee) if (einfo) { /* FIXME: REDRAW_DEBUG missing for now */ - einfo->info.window = ((struct _Ecore_Win32_Window *)ee->engine.win32.window)->window; + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; einfo->info.depth = ecore_win32_screen_depth_get(); einfo->info.rotation = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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; -#else - return 0; -#endif /* ! BUILD_ECORE_EVAS_DIRECT3D */ } +#endif /* BUILD_ECORE_EVAS_DIRECT3D */ +#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW static int _ecore_evas_engine_opengl_glew_init(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW Evas_Engine_Info_GL_Glew *einfo; const char *driver; int rmethod; @@ -1083,21 +1272,28 @@ _ecore_evas_engine_opengl_glew_init(Ecore_Evas *ee) if (einfo) { /* FIXME: REDRAW_DEBUG missing for now */ - einfo->info.window = ((struct _Ecore_Win32_Window *)ee->engine.win32.window)->window; + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; einfo->info.depth = ecore_win32_screen_depth_get(); - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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; -#else - return 0; -#endif /* ! BUILD_ECORE_EVAS_OPENGL_GLEW */ } +#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) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DIRECTDRAW Evas_Engine_Info_Software_DDraw *einfo; const char *driver; int rmethod; @@ -1118,16 +1314,26 @@ _ecore_evas_engine_software_16_ddraw_init(Ecore_Evas *ee) if (einfo) { /* FIXME: REDRAW_DEBUG missing for now */ - einfo->info.window = ((struct _Ecore_Win32_Window *)ee->engine.win32.window)->window; + einfo->info.window = ((struct _Ecore_Win32_Window *)ee->prop.window)->window; einfo->info.depth = ecore_win32_screen_depth_get(); einfo->info.rotation = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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 - return 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_DIRECTDRAW */ + 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, @@ -1136,7 +1342,6 @@ _ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee), int width, int height) { -#ifdef BUILD_ECORE_EVAS_WIN32 Ecore_Evas *ee; if (!ecore_win32_init()) @@ -1158,6 +1363,10 @@ _ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee), 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; @@ -1165,6 +1374,7 @@ _ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee), ee->prop.request_pos = 0; ee->prop.sticky = 0; /* FIXME: sticky to add */ + ee->prop.window = 0; /* init evas here */ ee->evas = evas_new(); @@ -1173,8 +1383,8 @@ _ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *ee), evas_output_viewport_set(ee->evas, 0, 0, width, height); ee->engine.win32.parent = parent; - ee->engine.win32.window = ecore_win32_window_new(parent, x, y, width, height); - if (!ee->engine.win32.window) + ee->prop.window = (Ecore_Window)ecore_win32_window_new(parent, x, y, width, height); + if (!ee->prop.window) { _ecore_evas_win32_shutdown(); free(ee); @@ -1188,30 +1398,52 @@ _ecore_evas_win32_new_internal(int (*_ecore_evas_engine_init)(Ecore_Evas *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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_win32_winid_str_get(ee->engine.win32.window), ee); + 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; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_WIN32 */ } +#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, @@ -1219,23 +1451,31 @@ ecore_evas_software_ddraw_new(Ecore_Win32_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_DDRAW 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; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_DDRAW */ } +#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, @@ -1243,23 +1483,31 @@ ecore_evas_software_16_ddraw_new(Ecore_Win32_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_DIRECTDRAW 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; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_DIRECTDRAW */ } +#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, @@ -1267,23 +1515,31 @@ ecore_evas_direct3d_new(Ecore_Win32_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_DIRECT3D 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; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_DIRECT3D */ } +#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, @@ -1291,30 +1547,43 @@ ecore_evas_gl_glew_new(Ecore_Win32_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_OPENGL_GLEW 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; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */ } +#endif /* BUILD_ECORE_EVAS_OPENGL_GLEW */ + + +#ifdef BUILD_ECORE_EVAS_WIN32 + EAPI Ecore_Win32_Window * -ecore_evas_win32_window_get(Ecore_Evas *ee) +ecore_evas_win32_window_get(const Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_WIN32 - return (Ecore_Win32_Window *) _ecore_evas_win32_window_get(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; - ee = NULL; -#endif /* BUILD_ECORE_EVAS_WIN32 */ } + +#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 index 29253e4..fe0054a 100644 --- a/src/lib/ecore_evas/ecore_evas_wince.c +++ b/src/lib/ecore_evas/ecore_evas_wince.c @@ -1,88 +1,69 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif #include /* for NULL */ -#include "Ecore.h" +#include #include "ecore_private.h" #ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN -# include "Ecore_WinCE.h" -# include "ecore_wince_private.h" +# 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 12 +#define ECORE_EVAS_EVENT_COUNT 9 static int _ecore_evas_init_count = 0; -static int _ecore_evas_fps_debug = 0; static Ecore_Event_Handler *ecore_evas_event_handlers[ECORE_EVAS_EVENT_COUNT]; -static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; -static Ecore_Evas *ecore_evases = NULL; -static Evas_Hash *ecore_evases_hash = NULL; - -static int _ecore_evas_wince_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event); - -static int _ecore_evas_wince_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event); - -static int _ecore_evas_wince_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event); -static int _ecore_evas_wince_event_mouse_button_up(void *data __UNUSED__, int type __UNUSED__, void *event); +static Eina_Bool _ecore_evas_wince_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event); -static int _ecore_evas_wince_event_mouse_move(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 int _ecore_evas_wince_event_mouse_in(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 int _ecore_evas_wince_event_mouse_out(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 int _ecore_evas_wince_event_window_damage(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 int _ecore_evas_wince_event_window_destroy(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 int _ecore_evas_wince_event_window_show(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 int _ecore_evas_wince_event_window_hide(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 int _ecore_evas_wince_event_window_delete_request(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 void +static int _ecore_evas_wince_render(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_BUFFER - Evas_List *ll; -#endif + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; -#ifdef BUILD_ECORE_EVAS_BUFFER - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) { - Ecore_Evas *ee2; - - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(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); } -#endif + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); if (ee->prop.avoid_damage) { - Evas_List *updates; - updates = evas_render_updates(ee->evas); if (updates) evas_render_updates_free(updates); } @@ -92,48 +73,20 @@ _ecore_evas_wince_render(Ecore_Evas *ee) { if (ee->shaped) { - Evas_List *updates; - updates = evas_render_updates(ee->evas); if (updates) evas_render_updates_free(updates); } else { - Evas_List *updates; - 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); -} - -static int -_ecore_evas_wince_idle_enter(void *data __UNUSED__) -{ - Ecore_List2 *l; - double t1 = 0.0; - double t2 = 0.0; - - if (_ecore_evas_fps_debug) - { - t1 = ecore_time_get(); - } - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - _ecore_evas_wince_render(ee); - } - if (_ecore_evas_fps_debug) - { - t2 = ecore_time_get(); - _ecore_evas_fps_debug_rendertime_add(t2 - t1); - } - return 1; + return rend; } static int @@ -143,26 +96,17 @@ _ecore_evas_wince_init(void) if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - if (getenv("ECORE_EVAS_FPS_DEBUG")) - _ecore_evas_fps_debug = 1; - - ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_wince_idle_enter, NULL); - - ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_WINCE_EVENT_KEY_DOWN, _ecore_evas_wince_event_key_down, NULL); - ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_WINCE_EVENT_KEY_UP, _ecore_evas_wince_event_key_up, NULL); - ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_wince_event_mouse_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_BUTTON_UP, _ecore_evas_wince_event_mouse_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_MOVE, _ecore_evas_wince_event_mouse_move, NULL); - ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_IN, _ecore_evas_wince_event_mouse_in, NULL); - ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_WINCE_EVENT_MOUSE_OUT, _ecore_evas_wince_event_mouse_out, NULL); - ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DAMAGE, _ecore_evas_wince_event_window_damage, NULL); - ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DESTROY, _ecore_evas_wince_event_window_destroy, NULL); - ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_SHOW, _ecore_evas_wince_event_window_show, NULL); - ecore_evas_event_handlers[10] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_HIDE, _ecore_evas_wince_event_window_hide, NULL); - ecore_evas_event_handlers[11] = ecore_event_handler_add(ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_wince_event_window_delete_request, NULL); - - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); - + 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; } @@ -172,14 +116,11 @@ _ecore_evas_wince_shutdown(void) _ecore_evas_init_count--; if (_ecore_evas_init_count == 0) { - int i; - - while (ecore_evases) _ecore_evas_free(ecore_evases); - for (i = 0; i < ECORE_EVAS_EVENT_COUNT; i++) - ecore_event_handler_del(ecore_evas_event_handlers[i]); - ecore_idle_enterer_del(ecore_evas_idle_enterer); - ecore_evas_idle_enterer = NULL; - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); + 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; @@ -187,221 +128,98 @@ _ecore_evas_wince_shutdown(void) return _ecore_evas_init_count; } -static char * -_ecore_evas_wince_winid_str_get(Ecore_WinCE_Window *window) -{ - static char id[9]; - const char *vals = "qWeRtYuIoP5-$&<~"; - unsigned int val; - - val = (unsigned int)window; - 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_wince_match(Ecore_WinCE_Window *window) -{ - Ecore_Evas *ee; - - ee = evas_hash_find(ecore_evases_hash, _ecore_evas_wince_winid_str_get(window)); - - return ee; -} - -static void -_ecore_evas_wince_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); -} - -static int -_ecore_evas_wince_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) +static Eina_Bool +_ecore_evas_wince_event_mouse_in(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_WinCE_Event_Key_Down *e; - - e = event; - ee = _ecore_evas_wince_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - evas_event_feed_key_down(ee->evas, e->keyname, e->keysymbol, e->keycompose, NULL, e->time, NULL); + Ecore_WinCE_Event_Mouse_In *e; - return 1; -} - -static int -_ecore_evas_wince_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_WinCE_Event_Key_Up *e; + INF("mouse in"); e = event; - ee = _ecore_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - evas_event_feed_key_up(ee->evas, e->keyname, e->keysymbol, e->keycompose, NULL, e->time, NULL); + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; - return 1; -} - -static int -_ecore_evas_wince_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_WinCE_Event_Mouse_Button_Down *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - - e = event; - ee = _ecore_evas_wince_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.wince.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); */ - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - printf ("feed evas event\n"); - evas_event_feed_mouse_down(ee->evas, e->button, flags, e->time, NULL); - - printf (" * ee event button down %f %d %d\n", e->time, e->x, e->y); + 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 int -_ecore_evas_wince_event_mouse_button_up(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) { - Ecore_Evas *ee; - Ecore_WinCE_Event_Mouse_Button_Up *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; + Ecore_Evas *ee; + Ecore_WinCE_Event_Mouse_Out *e; + + INF("mouse out"); - printf (" * ee event button up 0 \n"); e = event; - ee = _ecore_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; + /* FIXME to do */ /* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL); + _ecore_evas_mouse_move_process(ee, e->x, e->y, e->time); - printf (" * ee event button up\n"); + 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 int -_ecore_evas_wince_event_mouse_move(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) { - Ecore_Evas *ee; - Ecore_WinCE_Event_Mouse_Move *e; + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Focus_In *e; e = event; - ee = _ecore_evas_wince_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - _ecore_evas_wince_mouse_move_process(ee, e->x, e->y, e->time); + 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; - return 1; + 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_wince_event_mouse_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) { - Ecore_Evas *ee; - Ecore_WinCE_Event_Mouse_In *e; - - e = event; - ee = _ecore_evas_wince_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.wince.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_wince_mouse_move_process(ee, e->x, e->y, e->time); - printf (" * ee event mouse in\n"); - - return 1; -} - -static int -_ecore_evas_wince_event_mouse_out(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_WinCE_Event_Mouse_Out *e; + Ecore_Evas *ee; + Ecore_WinCE_Event_Window_Focus_Out *e; e = event; - ee = _ecore_evas_wince_match(e->window); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; - - /* FIXME to do */ -/* _ecore_evas_x_modifier_locks_update(ee, e->modifiers); */ - _ecore_evas_wince_mouse_move_process(ee, e->x, e->y, e->time); + 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_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); - printf (" * ee event mouse out\n"); - - return 1; + 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 +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_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; if (ee->prop.avoid_damage) { @@ -409,7 +227,6 @@ _ecore_evas_wince_event_window_damage(void *data __UNUSED__, int type __UNUSED__ } else { - printf (" * ee window event damage\n"); if (ee->rotation == 0) evas_damage_rectangle_add(ee->evas, e->x, @@ -439,34 +256,36 @@ _ecore_evas_wince_event_window_damage(void *data __UNUSED__, int type __UNUSED__ return 1; } -static int +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_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + 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); - printf (" * ee event destroy\n"); return 1; } -static int +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; - printf (" * ee window event show\n"); + INF("window show"); + e = event; - ee = _ecore_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + 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); @@ -474,16 +293,18 @@ _ecore_evas_wince_event_window_show(void *data __UNUSED__, int type __UNUSED__, return 1; } -static int +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_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + 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); @@ -491,19 +312,20 @@ _ecore_evas_wince_event_window_hide(void *data __UNUSED__, int type __UNUSED__, return 1; } -static int +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_evas_wince_match(e->window); + ee = ecore_event_window_match((Ecore_Window)e->window); if (!ee) return 1; /* pass on event */ - if (e->window != ee->engine.wince.window) return 1; + if (e->window != (Ecore_WinCE_Window *)ee->prop.window) return 1; if (ee->func.fn_delete_request) ee->func.fn_delete_request(ee); - printf (" * ee event delete\n"); return 1; } @@ -513,95 +335,108 @@ _ecore_evas_wince_event_window_delete_request(void *data __UNUSED__, int type __ static void _ecore_evas_wince_free(Ecore_Evas *ee) { - ecore_wince_window_del(ee->engine.wince.window); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_wince_winid_str_get(ee->engine.wince.window), ee); - ecore_evases = _ecore_list2_remove(ecore_evases, 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, - void (*func) (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) */ -/* { */ -/* if ((x != ee->x) || (y != ee->y)) */ -/* { */ -/* ee->x = x; */ -/* ee->y = y; */ -/* ecore_wince_window_move(ee->engine.wince.window, x, y); */ -/* if (ee->func.fn_move) ee->func.fn_move(ee); */ -/* } */ -/* } */ +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; -/* static void */ -/* _ecore_evas_wince_resize(Ecore_Evas *ee, int width, int height) */ -/* { */ -/* printf (" * _ecore_evas_wince_resize %d %d\n", width, height); */ -/* if ((ee->w != width) || (ee->h != height)) */ -/* { */ -/* ee->w = width; */ -/* ee->h = height; */ -/* ecore_wince_window_resize(ee->engine.wince.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); */ -/* } */ -/* } */ + 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_move_resize(Ecore_Evas *ee, int x, int y, int width, int height) */ -/* { */ -/* printf (" * _ecore_evas_wince_resize\n"); */ -/* 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(ee->engine.wince.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_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) */ @@ -613,84 +448,87 @@ _ecore_evas_wince_callback_delete_request_set(Ecore_Evas *ee, /* 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->engine.wince.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->engine.wince.window, &w, &h); */ -/* ecore_wince_window_resize(ee->engine.wince.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, */ +/* 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, */ +/* } */ +/* 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); */ +/* 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) { - printf (" * ee window show\n"); + INF("ecore evas show"); + ee->should_be_visible = 1; if (ee->prop.avoid_damage) _ecore_evas_wince_render(ee); - ecore_wince_window_show(ee->engine.wince.window); + ecore_wince_window_show((Ecore_WinCE_Window *)ee->prop.window); /* if (ee->prop.fullscreen) */ -/* ecore_wince_window_focus(ee->engine.wince.window); */ +/* ecore_wince_window_focus(ee->prop.window); */ } static void _ecore_evas_wince_hide(Ecore_Evas *ee) { - ecore_wince_window_hide(ee->engine.wince.window); + INF("ecore evas hide"); + + ecore_wince_window_hide((Ecore_WinCE_Window *)ee->prop.window); ee->should_be_visible = 0; } @@ -698,28 +536,30 @@ _ecore_evas_wince_hide(Ecore_Evas *ee) /* _ecore_evas_wince_raise(Ecore_Evas *ee) */ /* { */ /* if (!ee->prop.fullscreen) */ -/* ecore_wince_window_raise(ee->engine.wince.window); */ +/* ecore_wince_window_raise(ee->prop.window); */ /* else */ -/* ecore_wince_window_raise(ee->engine.wince.window); */ +/* 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->engine.wince.window); */ +/* ecore_wince_window_lower(ee->prop.window); */ /* else */ -/* ecore_wince_window_lower(ee->engine.wince.window); */ +/* ecore_wince_window_lower(ee->prop.window); */ /* } */ -/* static void */ -/* _ecore_evas_wince_title_set(Ecore_Evas *ee, const char *title) */ -/* { */ -/* if (ee->prop.title) free(ee->prop.title); */ -/* ee->prop.title = NULL; */ -/* if (title) ee->prop.title = strdup(title); */ -/* ecore_wince_window_title_set(ee->engine.wince.window, ee->prop.title); */ -/* } */ +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) */ @@ -729,7 +569,7 @@ _ecore_evas_wince_hide(Ecore_Evas *ee) /* 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->engine.wince.window, width, height); */ +/* ecore_wince_window_size_min_set(ee->prop.window, width, height); */ /* } */ /* static void */ @@ -740,7 +580,7 @@ _ecore_evas_wince_hide(Ecore_Evas *ee) /* 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->engine.wince.window, width, height); */ +/* ecore_wince_window_size_max_set(ee->prop.window, width, height); */ /* } */ /* static void */ @@ -751,7 +591,7 @@ _ecore_evas_wince_hide(Ecore_Evas *ee) /* 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->engine.wince.window, width, height); */ +/* ecore_wince_window_size_base_set(ee->prop.window, width, height); */ /* } */ /* static void */ @@ -762,7 +602,7 @@ _ecore_evas_wince_hide(Ecore_Evas *ee) /* 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->engine.wince.window, width, height); */ +/* ecore_wince_window_size_step_set(ee->prop.window, width, height); */ /* } */ static void @@ -775,12 +615,12 @@ _ecore_evas_wince_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho 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->engine.wince.window, 1); - return; + 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; @@ -788,24 +628,24 @@ _ecore_evas_wince_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho ee->prop.cursor.hot.x = hot_x; ee->prop.cursor.hot.y = hot_y; - ecore_wince_window_cursor_show(ee->engine.wince.window, 0); + 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); + 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_set(ee->engine.wince.window); */ -/* } */ +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) */ @@ -813,7 +653,7 @@ _ecore_evas_wince_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho /* /\* if (((ee->prop.borderless) && (on)) || *\/ */ /* /\* ((!ee->prop.borderless) && (!on))) return; *\/ */ /* ee->prop.iconified = on; */ -/* ecore_wince_window_iconified_set(ee->engine.wince.window, ee->prop.iconified); */ +/* ecore_wince_window_iconified_set(ee->prop.window, ee->prop.iconified); */ /* } */ /* static void */ @@ -822,100 +662,159 @@ _ecore_evas_wince_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ho /* if (((ee->prop.borderless) && (on)) || */ /* ((!ee->prop.borderless) && (!on))) return; */ /* ee->prop.borderless = on; */ -/* ecore_wince_window_borderless_set(ee->engine.wince.window, ee->prop.borderless); */ +/* ecore_wince_window_borderless_set(ee->prop.window, ee->prop.borderless); */ /* } */ static void _ecore_evas_wince_fullscreen_set(Ecore_Evas *ee, int on) { -/* if ((ee->prop.fullscreen && on) || */ -/* (!ee->prop.fullscreen && !on)) return; */ - -/* ee->engine.wince.state.fullscreen = on; */ -/* ecore_wince_window_fullscreen_set(ee->engine.wince.window, ee->prop.borderless); */ - /* FIXME: what to do with that code ?? */ -/* if (ee->should_be_visible) */ -/* ecore_x_netwm_state_request_send(ee->engine.x.win, ee->engine.x.win_root, */ -/* ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on); */ -/* else */ -/* _ecore_evas_wince_state_update(ee); */ + 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); + } + } } -#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ -static void * -_ecore_evas_wince_window_get(Ecore_Evas *ee) +static void +_ecore_evas_wince_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return ee->engine.wince.window; -#else - return NULL; -#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + 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); } -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE -static const Ecore_Evas_Engine_Func _ecore_wince_engine_func = +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, - NULL, //_ecore_evas_wince_move, - NULL, - NULL, //_ecore_evas_wince_resize, - NULL, //_ecore_evas_wince_move_resize, + 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_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, - NULL, //_ecore_evas_wince_title_set, - NULL, /* _ecore_evas_x_name_class_set */ + _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 */ - NULL, //_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 */ - _ecore_evas_wince_window_get + _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 }; -#endif /* BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ - /* API */ - -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE static Ecore_Evas * ecore_evas_software_wince_new_internal(int backend, Ecore_WinCE_Window *parent, int x, int y, int width, - int height) + int height, + int fullscreen) { Evas_Engine_Info_Software_16_WinCE *einfo; Ecore_Evas *ee; @@ -954,6 +853,10 @@ ecore_evas_software_wince_new_internal(int backend, 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; @@ -962,8 +865,8 @@ ecore_evas_software_wince_new_internal(int backend, ee->prop.sticky = 0; /* FIXME: sticky to add */ - ee->engine.wince.window = ecore_wince_window_new(parent, x, y, width, height); - if (!ee->engine.wince.window) + 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); @@ -971,6 +874,8 @@ ecore_evas_software_wince_new_internal(int backend, 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); @@ -982,31 +887,60 @@ ecore_evas_software_wince_new_internal(int backend, if (einfo) { /* FIXME: REDRAW_DEBUG missing for now */ - einfo->info.window = ((struct _Ecore_WinCE_Window *)ee->engine.wince.window)->window; + 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; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + 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(ee->engine.wince.window, backend); - ecore_wince_window_suspend_set(ee->engine.wince.window, einfo->func.suspend); - ecore_wince_window_resume_set(ee->engine.wince.window, einfo->func.resume); + 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; } - 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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_wince_winid_str_get(ee->engine.wince.window), ee); + 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 */ @@ -1017,16 +951,7 @@ ecore_evas_software_wince_new(Ecore_WinCE_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return ecore_evas_software_wince_new_internal(0, parent, x, y, width, height); -#else - return NULL; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + return ecore_evas_software_wince_new_internal(0, parent, x, y, width, height, 1); } EAPI Ecore_Evas * @@ -1036,16 +961,7 @@ ecore_evas_software_wince_fb_new(Ecore_WinCE_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return ecore_evas_software_wince_new_internal(1, parent, x, y, width, height); -#else - return NULL; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + return ecore_evas_software_wince_new_internal(1, parent, x, y, width, height, 1); } EAPI Ecore_Evas * @@ -1055,16 +971,7 @@ ecore_evas_software_wince_gapi_new(Ecore_WinCE_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return ecore_evas_software_wince_new_internal(2, parent, x, y, width, height); -#else - return NULL; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + return ecore_evas_software_wince_new_internal(2, parent, x, y, width, height, 1); } EAPI Ecore_Evas * @@ -1074,24 +981,33 @@ ecore_evas_software_wince_ddraw_new(Ecore_WinCE_Window *parent, int width, int height) { -#ifdef BUILD_ECORE_EVAS_SOFTWARE_16_WINCE - return ecore_evas_software_wince_new_internal(3, parent, x, y, width, height); -#else - return NULL; - parent = NULL; - x = 0; - y = 0; - width = 0; - height = 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_WINCE */ + return ecore_evas_software_wince_new_internal(3, parent, x, y, width, height, 1); } -EAPI Ecore_WinCE_Window * -ecore_evas_software_wince_window_get(Ecore_Evas *ee) +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 - return (Ecore_WinCE_Window *) _ecore_evas_wince_window_get(ee); + +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 */ } + +#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 index a3b1f01..ced4c2b 100644 --- a/src/lib/ecore_evas/ecore_evas_x.c +++ b/src/lib/ecore_evas/ecore_evas_x.c @@ -1,17 +1,12 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H -# include "config.h" +# include #endif -#include "Ecore.h" -#include "ecore_private.h" -#ifdef BUILD_ECORE_EVAS_X11 -# include "Ecore_X.h" -# include "Ecore_X_Atoms.h" -#endif +#include +#include + +#include +#include #include "ecore_evas_private.h" #include "Ecore_Evas.h" @@ -19,44 +14,128 @@ #ifdef BUILD_ECORE_EVAS_X11 static int _ecore_evas_init_count = 0; -static int _ecore_evas_fps_debug = 0; +static Ecore_Event_Handler *ecore_evas_event_handlers[13]; -static Ecore_Evas *ecore_evases = NULL; -static Evas_Hash *ecore_evases_hash = NULL; -static Ecore_Event_Handler *ecore_evas_event_handlers[18]; -static Ecore_Idle_Enterer *ecore_evas_idle_enterer = NULL; +static int leader_ref = 0; +static Ecore_X_Window leader_win = 0; -#ifdef HAVE_ECORE_X_XCB -static xcb_visualtype_t * -xcb_visualtype_get(xcb_screen_t *screen, xcb_visualid_t visual) +static void +_ecore_evas_x_hints_update(Ecore_Evas *ee) { - xcb_depth_iterator_t iter_depth; + 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 */); +} - if (!screen) return NULL; +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); +} - iter_depth = xcb_screen_allowed_depths_iterator(screen); - for (; iter_depth.rem; xcb_depth_next (&iter_depth)) +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) { - xcb_visualtype_iterator_t iter_vis; + 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); +} - iter_vis = xcb_depth_visuals_iterator(iter_depth.data); - for (; iter_vis.rem; --screen, xcb_visualtype_next (&iter_vis)) +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) { - if (visual == iter_vis.data->visual_id) - return iter_vis.data; + 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); +} - return NULL; +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; } -#endif /* HAVE_ECORE_X_XCB */ -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 -# ifdef HAVE_ECORE_X_XCB -/* noop */ -# else +# 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) +_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; @@ -64,1082 +143,1051 @@ _ecore_evas_x_gl_window_new(Ecore_Evas *ee, Ecore_X_Window parent, int x, int y, einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); if (einfo) { - XSetWindowAttributes attr; - int screen; - - /* FIXME: this is inefficient as its a round trip */ - screen = DefaultScreen(ecore_x_display_get()); - 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]) - { - screen = i; - break; - } - } - } - free(roots); - } - } - attr.backing_store = NotUseful; - attr.override_redirect = override; - attr.colormap = einfo->func.best_colormap_get(ecore_x_display_get(), screen); - 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(ecore_x_display_get(), - parent, - x, y, - w, h, 0, - einfo->func.best_depth_get(ecore_x_display_get(), screen), - InputOutput, - einfo->func.best_visual_get(ecore_x_display_get(), screen), - CWBackingStore | CWColormap | - CWBackPixmap | CWBorderPixel | - CWBitGravity | CWEventMask | - CWOverrideRedirect, - &attr); - einfo->info.display = ecore_x_display_get(); - einfo->info.visual = einfo->func.best_visual_get(ecore_x_display_get(), screen); - einfo->info.colormap = einfo->func.best_colormap_get(ecore_x_display_get(), screen); - einfo->info.drawable = win; - einfo->info.depth = einfo->func.best_depth_get(ecore_x_display_get(), screen); - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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]; + } +#ifdef EVAS_ENGINE_GL_X11_SWAP_MODE_EXISTS + else if (opt[op] == ECORE_EVAS_GL_X11_OPT_SWAP_MODE) + { + op++; + if ((evas_version->major >= 1) && + (evas_version->minor >= 7) && + (evas_version->micro >= 99)) + einfo->swap_mode = opt[op]; + } +#endif + } + } + + /* 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; - } + win = 0; + return win; } -#endif /* HAVE_ECORE_X_XCB */ #endif -static void +static int _ecore_evas_x_render(Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_BUFFER - Evas_List *ll; -#endif + int rend = 0; + Eina_List *updates = NULL; + Eina_List *ll; + Ecore_Evas *ee2; -#ifdef BUILD_ECORE_EVAS_BUFFER - for (ll = ee->sub_ecore_evas; ll; ll = ll->next) - { - 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; - ee2 = ll->data; - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - _ecore_evas_buffer_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(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); } -#endif + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + updates = evas_render_updates(ee->evas); if (ee->prop.avoid_damage) { - Evas_List *updates, *l; - - updates = evas_render_updates(ee->evas); -#if 0 -// if (ee->w == 640) - { - for (l = updates; l; l = l->next) - { - Evas_Rectangle *r; - - r = l->data; - printf(" UP render [%p] %ix%i, [%i %i %ix%i]\n", - ee, ee->w, ee->h, r->x, r->y, r->w, r->h); - } - } -#endif - if (ee->engine.x.using_bg_pixmap) - { - if (updates) - { - for (l = updates; l; l = l->next) - { - Evas_Rectangle *r; - - r = l->data; - ecore_x_window_area_clear(ee->engine.x.win, r->x, r->y, r->w, r->h); - } - if ((ee->shaped) && (updates)) - ecore_x_window_shape_mask_set(ee->engine.x.win, ee->engine.x.mask); - if ((ee->alpha) && (updates)) - ecore_x_window_shape_input_mask_set(ee->engine.x.win, ee->engine.x.mask); - } - if (updates) - { - evas_render_updates_free(updates); - _ecore_evas_idle_timeout_update(ee); - } - } - else - { -#ifdef HAVE_ECORE_X_XCB -#warning [XCB] No Region code -#else - for (l = updates; l; l = l->next) - { - Evas_Rectangle *r; - XRectangle xr; - Region tmpr; - - if (!ee->engine.x.damages) - ee->engine.x.damages = XCreateRegion(); - r = l->data; - tmpr = XCreateRegion(); - if (ee->rotation == 0) - { - xr.x = r->x; - xr.y = r->y; - xr.width = r->w; - xr.height = r->h; - } - else if (ee->rotation == 90) - { - xr.x = r->y; - xr.y = ee->h - r->x - r->w; - xr.width = r->h; - xr.height = r->w; - } - else if (ee->rotation == 180) - { - xr.x = ee->w - r->x - r->w; - xr.y = ee->h - r->y - r->h; - xr.width = r->w; - xr.height = r->h; - } - else if (ee->rotation == 270) - { - xr.x = ee->w - r->y - r->h; - xr.y = r->x; - xr.width = r->h; - xr.height = r->w; - } - XUnionRectWithRegion(&xr, ee->engine.x.damages, tmpr); - XDestroyRegion(ee->engine.x.damages); - ee->engine.x.damages = tmpr; - } - if (ee->engine.x.damages) - { -#if 0 -// if (ee->w == 640) - printf(" --COPY PIXMAP\n"); -#endif - /* if we have a damage pixmap - we can avoid exposures by - * disabling them just for setting the mask */ - ecore_x_event_mask_set(ee->engine.x.win, - ECORE_X_EVENT_MASK_KEY_DOWN | - ECORE_X_EVENT_MASK_KEY_UP | - ECORE_X_EVENT_MASK_MOUSE_DOWN | - ECORE_X_EVENT_MASK_MOUSE_UP | - ECORE_X_EVENT_MASK_MOUSE_IN | - ECORE_X_EVENT_MASK_MOUSE_OUT | - ECORE_X_EVENT_MASK_MOUSE_MOVE | -// ECORE_X_EVENT_MASK_WINDOW_DAMAGE | - ECORE_X_EVENT_MASK_WINDOW_VISIBILITY | - ECORE_X_EVENT_MASK_WINDOW_CONFIGURE | - ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE | - ECORE_X_EVENT_MASK_WINDOW_PROPERTY | - ECORE_X_EVENT_MASK_WINDOW_COLORMAP - ); - if ((ee->shaped) && (updates)) - ecore_x_window_shape_mask_set(ee->engine.x.win, ee->engine.x.mask); - /* and re-enable them again */ - ecore_x_event_mask_set(ee->engine.x.win, - ECORE_X_EVENT_MASK_KEY_DOWN | - ECORE_X_EVENT_MASK_KEY_UP | - ECORE_X_EVENT_MASK_MOUSE_DOWN | - ECORE_X_EVENT_MASK_MOUSE_UP | - ECORE_X_EVENT_MASK_MOUSE_IN | - ECORE_X_EVENT_MASK_MOUSE_OUT | - ECORE_X_EVENT_MASK_MOUSE_MOVE | - ECORE_X_EVENT_MASK_WINDOW_DAMAGE | - ECORE_X_EVENT_MASK_WINDOW_VISIBILITY | - ECORE_X_EVENT_MASK_WINDOW_CONFIGURE | - ECORE_X_EVENT_MASK_WINDOW_FOCUS_CHANGE | - ECORE_X_EVENT_MASK_WINDOW_PROPERTY | - ECORE_X_EVENT_MASK_WINDOW_COLORMAP - ); - XSetRegion(ecore_x_display_get(), ee->engine.x.gc, ee->engine.x.damages); - /* debug rendering */ - /* - XSetForeground(ecore_x_display_get(), ee->engine.x.gc, rand()); - XFillRectangle(ecore_x_display_get(), ee->engine.x.win, ee->engine.x.gc, - 0, 0, ee->w, ee->h); - XSync(ecore_x_display_get(), False); - usleep(20000); - XSync(ecore_x_display_get(), False); - */ - ecore_x_pixmap_paste(ee->engine.x.pmap, ee->engine.x.win, ee->engine.x.gc, - 0, 0, ee->w, ee->h, 0, 0); - XDestroyRegion(ee->engine.x.damages); - ee->engine.x.damages = 0; - } -#endif /* HAVE_ECORE_X_XCB */ - if (updates) - { - evas_render_updates_free(updates); - _ecore_evas_idle_timeout_update(ee); - } - } + 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 (ee->shaped) - { - Evas_List *updates; - - updates = evas_render_updates(ee->evas); - if (updates) - { - ecore_x_window_shape_mask_set(ee->engine.x.win, ee->engine.x.mask); - evas_render_updates_free(updates); - _ecore_evas_idle_timeout_update(ee); - } - } - else - { - Evas_List *updates; - - updates = evas_render_updates(ee->evas); - if (updates) - { -#if 0 -// if (ee->w == 640) - { - Evas_List *l; - - printf("RENDER [%p] [%i] %ix%i\n", - ee, ee->visible, ee->w, ee->h); - for (l = updates; l; l = l->next) - { - Evas_Rectangle *r; - - r = l->data; - printf(" render [%i %i %ix%i]\n", - r->x, r->y, r->w, r->h); - } - } -#endif - evas_render_updates_free(updates); - if (ee->alpha) - ecore_x_window_shape_input_mask_set(ee->engine.x.win, ee->engine.x.mask); - _ecore_evas_idle_timeout_update(ee); - } - } + ((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; -static void -_ecore_evas_x_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); + 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; + } } - 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); -} - -static char * -_ecore_evas_x_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_x_match(Ecore_X_Window win) -{ - Ecore_Evas *ee; - - ee = evas_hash_find(ecore_evases_hash, _ecore_evas_x_winid_str_get(win)); - return ee; + return rend; } static void _ecore_evas_x_resize_shape(Ecore_Evas *ee) { - if (!strcmp(ee->driver, "software_x11") || !strcmp(ee->driver, "software_xcb")) + if (!strcmp(ee->driver, "software_x11")) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -# else - Evas_Engine_Info_Software_X11 *einfo; - - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - if (einfo) - { -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - xcb_rectangle_t rectangle; - Ecore_X_GC gc; - uint32_t value_list; -# else - GC gc; - XGCValues gcv; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - gc = xcb_generate_id(ecore_x_connection_get()); - value_list = 0; - xcb_create_gc(ecore_x_connection_get(), gc, ee->engine.x.mask, - XCB_GC_FOREGROUND, &value_list); - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = ee->w; - rectangle.height = ee->h; - xcb_poly_fill_rectangle(ecore_x_connection_get(), ee->engine.x.mask, gc, - 1, &rectangle); - xcb_free_gc(ecore_x_connection_get(), gc); -# else - gcv.foreground = 0; - gc = XCreateGC(ecore_x_display_get(), ee->engine.x.mask, - GCForeground, - &gcv); - XFillRectangle(ecore_x_display_get(), ee->engine.x.mask, gc, - 0, 0, ee->w, ee->h); - XFreeGC(ecore_x_display_get(), gc); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - } -#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 || BUILD_ECORE_EVAS_SOFTWARE_XCB */ - } - else if (!strcmp(ee->driver, "xrender_x11") || !strcmp(ee->driver, "xrender_xcb")) - { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - Evas_Engine_Info_XRender_Xcb *einfo; - - einfo = (Evas_Engine_Info_XRender_Xcb *)evas_engine_info_get(ee->evas); -# else - Evas_Engine_Info_XRender_X11 *einfo; - - einfo = (Evas_Engine_Info_XRender_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - if (einfo) - { -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - xcb_rectangle_t rectangle; - Ecore_X_GC gc; - uint32_t value_list; -# else - GC gc; - XGCValues gcv; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - gc = xcb_generate_id(ecore_x_connection_get()); - value_list = 0; - xcb_create_gc(ecore_x_connection_get(), gc, ee->engine.x.mask, - XCB_GC_FOREGROUND, &value_list); - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = ee->w; - rectangle.height = ee->h; - xcb_poly_fill_rectangle(ecore_x_connection_get(), ee->engine.x.mask, gc, - 1, &rectangle); - xcb_free_gc(ecore_x_connection_get(), gc); -# else - gcv.foreground = 0; - gc = XCreateGC(ecore_x_display_get(), ee->engine.x.mask, - GCForeground, - &gcv); - XFillRectangle(ecore_x_display_get(), ee->engine.x.mask, gc, - 0, 0, ee->w, ee->h); - XFreeGC(ecore_x_display_get(), gc); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - - } -#endif /* BUILD_ECORE_EVAS_XRENDER_X11 || BUILD_ECORE_EVAS_XRENDER_XCB */ + 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) - { - GC gc; - XGCValues gcv; - - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - } + 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 */ } -} - -static void -_ecore_evas_x_modifier_locks_update(Ecore_Evas *ee, int modifiers) -{ - if (modifiers & ECORE_X_MODIFIER_SHIFT) - evas_key_modifier_on(ee->evas, "Shift"); - else - evas_key_modifier_off(ee->evas, "Shift"); - if (modifiers & ECORE_X_MODIFIER_CTRL) - evas_key_modifier_on(ee->evas, "Control"); - else - evas_key_modifier_off(ee->evas, "Control"); - if (modifiers & ECORE_X_MODIFIER_ALT) - evas_key_modifier_on(ee->evas, "Alt"); - else - evas_key_modifier_off(ee->evas, "Alt"); - if (modifiers & ECORE_X_MODIFIER_WIN) - { - evas_key_modifier_on(ee->evas, "Super"); - evas_key_modifier_on(ee->evas, "Hyper"); - } - else + if (!strcmp(ee->driver, "software_8_x11")) { - evas_key_modifier_off(ee->evas, "Super"); - evas_key_modifier_off(ee->evas, "Hyper"); - } - if (modifiers & ECORE_X_LOCK_SCROLL) - evas_key_lock_on(ee->evas, "Scroll_Lock"); - else - evas_key_lock_off(ee->evas, "Scroll_Lock"); - if (modifiers & ECORE_X_LOCK_NUM) - evas_key_lock_on(ee->evas, "Num_Lock"); - else - evas_key_lock_off(ee->evas, "Num_Lock"); - if (modifiers & ECORE_X_LOCK_CAPS) - evas_key_lock_on(ee->evas, "Caps_Lock"); - else - evas_key_lock_off(ee->evas, "Caps_Lock"); -} +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) + Evas_Engine_Info_Software_8_X11 *einfo; -static int -_ecore_evas_x_event_key_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_X_Event_Key_Down *e; - - e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - evas_event_feed_key_down(ee->evas, e->keyname, e->keysymbol, e->key_compose, NULL, e->time, NULL); - return 1; -} - -static int -_ecore_evas_x_event_key_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_X_Event_Key_Up *e; - - e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - evas_event_feed_key_up(ee->evas, e->keyname, e->keysymbol, e->key_compose, NULL, e->time, NULL); - return 1; -} - -static int -_ecore_evas_x_event_mouse_button_down(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_X_Event_Mouse_Button_Down *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - - e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_down(ee->evas, e->button, flags, e->time, NULL); - return 1; -} - -static int -_ecore_evas_x_event_mouse_button_up(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_X_Event_Mouse_Button_Up *e; - Evas_Button_Flags flags = EVAS_BUTTON_NONE; - - e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - if (e->double_click) flags |= EVAS_BUTTON_DOUBLE_CLICK; - if (e->triple_click) flags |= EVAS_BUTTON_TRIPLE_CLICK; - evas_event_feed_mouse_up(ee->evas, e->button, flags, e->time, NULL); - return 1; -} - -static int -_ecore_evas_x_event_mouse_wheel(void *data __UNUSED__, int type __UNUSED__, void *event) -{ - Ecore_Evas *ee; - Ecore_X_Event_Mouse_Wheel *e; - - e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - evas_event_feed_mouse_wheel(ee->evas, e->direction, e->z, e->time, NULL); - - return 1; + 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 int +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_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; + 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; - int sticky; - -#ifdef HAVE_ECORE_X_XCB - ecore_x_netwm_window_state_get_prefetch(e->win); -#endif /* HAVE_ECORE_X_XCB */ - sticky = 0; - - /* TODO: we need to move those to the end, with if statements */ - ee->engine.x.state.modal = 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->prop.fullscreen = 0; - ee->engine.x.state.fullscreen = 0; - ee->engine.x.state.above = 0; - ee->engine.x.state.below = 0; - -#ifdef HAVE_ECORE_X_XCB - ecore_x_netwm_window_state_get_fetch(); -#endif /* HAVE_ECORE_X_XCB */ - 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; - break; - case ECORE_X_WINDOW_STATE_STICKY: - if (ee->prop.sticky && ee->engine.x.state.sticky) - break; - - sticky = 1; - ee->prop.sticky = 1; - ee->engine.x.state.sticky = 1; - if (ee->func.fn_sticky) ee->func.fn_sticky(ee); - break; - case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT: - ee->engine.x.state.maximized_v = 1; - break; - case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ: - ee->engine.x.state.maximized_h = 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; - break; - case ECORE_X_WINDOW_STATE_SKIP_PAGER: - ee->engine.x.state.skip_pager = 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); - } -#ifdef HAVE_ECORE_X_XCB - ecore_xcb_reply_free(); -#endif /* HAVE_ECORE_X_XCB */ - - if (ee->prop.sticky && !sticky) - { - ee->prop.sticky = 0; - ee->engine.x.state.sticky = 0; - if (ee->func.fn_unsticky) ee->func.fn_unsticky(ee); - } + 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; + } - return 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 int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; + 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) ee->draw_ok = 0; - else ee->draw_ok = 1; - return 1; + 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 int -_ecore_evas_x_event_mouse_move(void *data __UNUSED__, int type __UNUSED__, void *event) +static Eina_Bool +_ecore_evas_x_event_client_message(void *data __UNUSED__, int type __UNUSED__, void *event) { Ecore_Evas *ee; - Ecore_X_Event_Mouse_Move *e; + Ecore_X_Event_Client_Message *e; e = event; - ee = _ecore_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - _ecore_evas_x_mouse_move_process(ee, e->x, e->y, e->time); - return 1; + 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 int +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_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; -/* + 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) { - 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]); + 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; } - */ -// disable. causes mroe 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->func.fn_mouse_in) ee->func.fn_mouse_in(ee); - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - evas_event_feed_mouse_in(ee->evas, e->time, NULL); - _ecore_evas_x_mouse_move_process(ee, e->x, e->y, e->time); - return 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; -/* + 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) { - 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]); + 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; } - */ -// 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; */ - _ecore_evas_x_modifier_locks_update(ee, e->modifiers); - _ecore_evas_x_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); - return 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if ((!ee) || (ee->ignore_events)) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - if (ee->prop.fullscreen) - ecore_x_window_focus(ee->engine.x.win); + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - if (ee->engine.x.using_bg_pixmap) return 1; + 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) { -#ifdef HAVE_ECORE_X_XCB -# warning [XCB] No Region code -#else - XRectangle xr; - Region tmpr; - - if (!ee->engine.x.damages) ee->engine.x.damages = XCreateRegion(); - tmpr = XCreateRegion(); - xr.x = e->x; - xr.y = e->y; - xr.width = e->w; - xr.height = e->h; - XUnionRectWithRegion(&xr, ee->engine.x.damages, tmpr); - XDestroyRegion(ee->engine.x.damages); - ee->engine.x.damages = tmpr; + 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_Region tmpr; - - if (!ee->engine.x.damages) ee->engine.x.damages = XCreateRegion(); - tmpr = XCreateRegion(); - rect.x = e->x; - rect.y = e->y; - rect.width = e->w; - rect.height = e->h; - XUnionRectWithRegion(&rect, ee->engine.x.damages, tmpr); - XDestroyRegion(ee->engine.x.damages); - ee->engine.x.damages = tmpr; + 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; */ -#endif /* ! HAVE_ECORE_X_XCB */ } 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); + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - if (ee->engine.x.direct_resize) return 1; + 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; - if (ee->func.fn_move) ee->func.fn_move(ee); - } + 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; - 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_x_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); + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - if (ee->visible) return 0; /* dont pass it on */ + 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 1; + return ECORE_CALLBACK_PASS_ON; } -static int +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_evas_x_match(e->win); - if (!ee) return 1; /* pass on event */ - if (e->win != ee->engine.x.win) return 1; - if (!ee->visible) return 0; /* dont pass it on */ + 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 1; + return ECORE_CALLBACK_PASS_ON; } /* FIXME, should be in idler */ @@ -1147,26 +1195,19 @@ _ecore_evas_x_event_window_hide(void *data __UNUSED__, int type __UNUSED__, void static void _ecore_evas_x_size_pos_hints_update(Ecore_Evas *ee) { -# ifdef HAVE_ECORE_X_XCB - ecore_x_icccm_size_pos_hints_get_prefetch(ee->engine.x.win); - ecore_x_icccm_size_pos_hints_get_fetch(); -# endif /* HAVE_ECORE_X_XCB */ - ecore_x_icccm_size_pos_hints_set(ee->engine.x.win, - 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 */, - 0 /* min_aspect */, - 0 /* max_aspect */); -# ifdef HAVE_ECORE_X_XCB - ecore_xcb_reply_free(); -# endif /* HAVE_ECORE_X_XCB */ + 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 */ @@ -1174,38 +1215,34 @@ static void _ecore_evas_x_state_update(Ecore_Evas *ee) { Ecore_X_Window_State state[10]; - int num; + int num = 0; - num = 0; - - /* - if (bd->client.netwm.state.modal) + if (ee->prop.modal) state[num++] = ECORE_X_WINDOW_STATE_MODAL; - */ - if (ee->engine.x.state.sticky) + if (ee->prop.sticky) state[num++] = ECORE_X_WINDOW_STATE_STICKY; - /* - if (bd->client.netwm.state.maximized_v) + if (ee->prop.maximized) state[num++] = ECORE_X_WINDOW_STATE_MAXIMIZED_VERT; - if (bd->client.netwm.state.maximized_h) + 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 (bd->client.netwm.state.skip_taskbar) +// 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 (bd->client.netwm.state.skip_pager) + 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 (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->engine.x.win, state, num); + ecore_x_netwm_window_state_set(ee->prop.window, state, num); } static void @@ -1213,881 +1250,1217 @@ _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->engine.x.win, - 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->engine.x.win, - 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->engine.x.win, - 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->engine.x.win, - 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->engine.x.win, - 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->engine.x.win, - ee->engine.x.win_root, - ECORE_X_WINDOW_STATE_ABOVE, -1, 0); - } - } + /* 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); - } - } + /* 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_idle_enter(void *data __UNUSED__) -{ - Ecore_List2 *l; - double t1 = 0.0; - double t2 = 0.0; - - if (_ecore_evas_fps_debug) - { - t1 = ecore_time_get(); - } - for (l = (Ecore_List2 *)ecore_evases; l; l = l->next) - { - Ecore_Evas *ee; - - ee = (Ecore_Evas *)l; - _ecore_evas_x_render(ee); - } - ecore_x_flush(); - if (_ecore_evas_fps_debug) - { - t2 = ecore_time_get(); - _ecore_evas_fps_debug_rendertime_add(t2 - t1); - } - return 1; -} - -static int _ecore_evas_x_init(void) { _ecore_evas_init_count++; if (_ecore_evas_init_count > 1) return _ecore_evas_init_count; - if (getenv("ECORE_EVAS_FPS_DEBUG")) _ecore_evas_fps_debug = 1; - ecore_evas_idle_enterer = ecore_idle_enterer_add(_ecore_evas_x_idle_enter, NULL); - ecore_evas_event_handlers[0] = ecore_event_handler_add(ECORE_X_EVENT_KEY_DOWN, _ecore_evas_x_event_key_down, NULL); - ecore_evas_event_handlers[1] = ecore_event_handler_add(ECORE_X_EVENT_KEY_UP, _ecore_evas_x_event_key_up, NULL); - ecore_evas_event_handlers[2] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_BUTTON_DOWN, _ecore_evas_x_event_mouse_button_down, NULL); - ecore_evas_event_handlers[3] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_BUTTON_UP, _ecore_evas_x_event_mouse_button_up, NULL); - ecore_evas_event_handlers[4] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_MOVE, _ecore_evas_x_event_mouse_move, NULL); - ecore_evas_event_handlers[5] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_IN, _ecore_evas_x_event_mouse_in, NULL); - ecore_evas_event_handlers[6] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_OUT, _ecore_evas_x_event_mouse_out, NULL); - ecore_evas_event_handlers[7] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_IN, _ecore_evas_x_event_window_focus_in, NULL); - ecore_evas_event_handlers[8] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, _ecore_evas_x_event_window_focus_out, NULL); - ecore_evas_event_handlers[9] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DAMAGE, _ecore_evas_x_event_window_damage, NULL); - ecore_evas_event_handlers[10] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, _ecore_evas_x_event_window_destroy, NULL); - ecore_evas_event_handlers[11] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE, _ecore_evas_x_event_window_configure, NULL); - ecore_evas_event_handlers[12] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, _ecore_evas_x_event_window_delete_request, NULL); - ecore_evas_event_handlers[13] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, _ecore_evas_x_event_window_show, NULL); - ecore_evas_event_handlers[14] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, _ecore_evas_x_event_window_hide, NULL); - ecore_evas_event_handlers[15] = ecore_event_handler_add(ECORE_X_EVENT_MOUSE_WHEEL, _ecore_evas_x_event_mouse_wheel, NULL); - ecore_evas_event_handlers[16] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, _ecore_evas_x_event_property_change, NULL); - ecore_evas_event_handlers[17] = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, _ecore_evas_x_event_visibility_change, NULL); - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_init(); + 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_x_window_del(ee->engine.x.win); - if (ee->engine.x.pmap) ecore_x_pixmap_del(ee->engine.x.pmap); - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - if (ee->engine.x.gc) ecore_x_gc_del(ee->engine.x.gc); -#ifdef HAVE_ECORE_X_XCB -# warning [XCB] No Region code -#else - if (ee->engine.x.damages) XDestroyRegion(ee->engine.x.damages); -#endif /* ! HAVE_ECORE_X_XCB */ + _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; -#ifdef HAVE_ECORE_X_XCB -# warning [XCB] No Region code -#else - ee->engine.x.damages = 0; -#endif /* ! HAVE_ECORE_X_XCB */ - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); + ee->engine.x.damages = NULL; + ecore_event_window_unregister(ee->prop.window); while (ee->engine.x.win_extra) { - Ecore_X_Window *winp; + Ecore_X_Window *winp; - winp = ee->engine.x.win_extra->data; - ee->engine.x.win_extra = evas_list_remove_list(ee->engine.x.win_extra, ee->engine.x.win_extra); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_x_winid_str_get(*winp), ee); - free(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_evases = _ecore_list2_remove(ecore_evases, ee); _ecore_evas_x_shutdown(); ecore_x_shutdown(); } -/* FIXME: round trip */ static void -_ecore_evas_x_callback_delete_request_set(Ecore_Evas *ee, void (*func) (Ecore_Evas *ee)) -{ -#ifdef HAVE_ECORE_X_XCB - ecore_x_icccm_protocol_get_prefetch(ee->engine.x.win); - ecore_x_icccm_protocol_get_fetch(); -#endif /* HAVE_ECORE_X_XCB */ - if (func) - ecore_x_icccm_protocol_set(ee->engine.x.win, ECORE_X_WM_PROTOCOL_DELETE_REQUEST, 1); - else - ecore_x_icccm_protocol_set(ee->engine.x.win, ECORE_X_WM_PROTOCOL_DELETE_REQUEST, 0); +_ecore_evas_x_callback_delete_request_set(Ecore_Evas *ee, Ecore_Evas_Event_Cb func) +{ ee->func.fn_delete_request = func; -#ifdef HAVE_ECORE_X_XCB - ecore_xcb_reply_free(); -#endif /* HAVE_ECORE_X_XCB */ + _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->engine.x.win, 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); - } - } + 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 { - ecore_x_window_move(ee->engine.x.win, 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->engine.x.managed) - { - ee->x = x; - ee->y = y; - } + 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); - } + 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)) - { - ecore_x_window_resize(ee->engine.x.win, 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); - } - 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); - } + 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; + } } - else - ecore_x_window_resize(ee->engine.x.win, w, h); } -static void -_ecore_evas_x_move_resize(Ecore_Evas *ee, int x, int y, int w, int 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->engine.x.win, 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); - } - } +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; + 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); + } + 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 { - ecore_x_window_move_resize(ee->engine.x.win, x, y, w, h); - if (!ee->engine.x.managed) - { - ee->x = x; - ee->y = y; - } + 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); } } -static void -_ecore_evas_x_rotation_set_internal(Ecore_Evas *ee, int rotation, - Evas_Engine_Info *einfo) -{ - int rot_dif; +#define _USE_WIN_ROT_EFFECT 1 - rot_dif = ee->rotation - rotation; - if (rot_dif < 0) rot_dif = -rot_dif; +#if _USE_WIN_ROT_EFFECT +static void _ecore_evas_x_flush_pre(void *data, Evas *e __UNUSED__, void *event_info __UNUSED__); - if (rot_dif != 180) - { - int minw, minh, maxw, maxh, basew, baseh, stepw, steph; - - evas_engine_info_set(ee->evas, einfo); - if (!ee->prop.fullscreen) - { - ecore_x_window_resize(ee->engine.x.win, ee->h, ee->w); - ee->expecting_resize.w = ee->h; - ee->expecting_resize.h = ee->w; - } - else - { - int w, h; - - ecore_x_window_size_get(ee->engine.x.win, &w, &h); - ecore_x_window_resize(ee->engine.x.win, 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_x_mouse_move_process(ee, ee->mouse.x, ee->mouse.y, - ecore_x_current_time_get()); - } - else - { - evas_engine_info_set(ee->evas, einfo); - ee->rotation = rotation; - _ecore_evas_x_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); - } +typedef struct _Ecore_Evas_X_Rotation_Effect Ecore_Evas_X_Rotation_Effect; +struct _Ecore_Evas_X_Rotation_Effect +{ + Eina_Bool wait_for_comp_reply; +}; - 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 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) +_ecore_evas_x_rotation_set(Ecore_Evas *ee, int rotation, int resize) { if (ee->rotation == rotation) return; - if (!strcmp(ee->driver, "gl_x11")) return; if (!strcmp(ee->driver, "xrender_x11")) return; - if (!strcmp(ee->driver, "software_x11") || !strcmp(ee->driver, "software_xcb")) - { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -# else - Evas_Engine_Info_Software_X11 *einfo; +#if _USE_WIN_ROT_EFFECT + int angles[2]; + angles[0] = rotation; + angles[1] = ee->rotation; +#endif /* end of _USE_WIN_ROT_EFFECT */ - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - if (!einfo) return; - einfo->info.rotation = rotation; - _ecore_evas_x_rotation_set_internal - (ee, rotation, (Evas_Engine_Info *)einfo); -#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 || BUILD_ECORE_EVAS_SOFTWARE_XCB */ + 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, (Evas_Engine_Info *)einfo); + 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)) || ((!ee->shaped) && (!shaped))) - return; - if (!strcmp(ee->driver, "gl_x11")) return; - if (!strcmp(ee->driver, "software_x11") || !strcmp(ee->driver, "software_xcb")) + if ((ee->shaped == shaped)) return; + if (!strcmp(ee->driver, "opengl_x11")) return; + if (!strcmp(ee->driver, "software_x11")) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; - - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -# else - Evas_Engine_Info_Software_X11 *einfo; - - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - ee->shaped = shaped; - if (einfo) - { - if (ee->shaped) - { -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - xcb_rectangle_t rectangle; - Ecore_X_GC gc; - uint32_t value_list; -# else - GC gc; - XGCValues gcv; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - if (!ee->engine.x.mask) - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - gc = xcb_generate_id(ecore_x_connection_get()); - value_list = 0; - xcb_create_gc(ecore_x_connection_get(), - gc, ee->engine.x.mask, - XCB_GC_FOREGROUND, - &value_list); - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = ee->w; - rectangle.height = ee->h; - xcb_poly_fill_rectangle(ecore_x_connection_get(), - ee->engine.x.mask, gc, - 1, &rectangle); - xcb_free_gc(ecore_x_connection_get(), gc); -# else - gcv.foreground = 0; - gc = XCreateGC(ecore_x_display_get(), ee->engine.x.mask, - GCForeground, - &gcv); - XFillRectangle(ecore_x_display_get(), ee->engine.x.mask, gc, - 0, 0, ee->w, ee->h); - XFreeGC(ecore_x_display_get(), gc); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - else - { - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - einfo->info.mask = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - } -#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 || BUILD_ECORE_EVAS_SOFTWARE_XCB */ - } - else if (!strcmp(ee->driver, "xrender_x11") || !strcmp(ee->driver, "xrender_xcb")) - { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - Evas_Engine_Info_XRender_Xcb *einfo; -# else - Evas_Engine_Info_XRender_X11 *einfo; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; - ee->shaped = shaped; -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - einfo = (Evas_Engine_Info_XRender_Xcb *)evas_engine_info_get(ee->evas); -# else - einfo = (Evas_Engine_Info_XRender_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - if (einfo) - { - if (ee->shaped) - { -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - xcb_rectangle_t rectangle; - Ecore_X_GC gc; - uint32_t value_list; -# else - GC gc; - XGCValues gcv; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - - if (!ee->engine.x.mask) - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - gc = xcb_generate_id(ecore_x_connection_get()); - value_list = 0; - xcb_create_gc(ecore_x_connection_get(), - gc, ee->engine.x.mask, - XCB_GC_FOREGROUND, - &value_list); - rectangle.x = 0; - rectangle.y = 0; - rectangle.width = ee->w; - rectangle.height = ee->h; - xcb_poly_fill_rectangle(ecore_x_connection_get(), - ee->engine.x.mask, gc, - 1, &rectangle); - xcb_free_gc(ecore_x_connection_get(), gc); -# else - gcv.foreground = 0; - gc = XCreateGC(ecore_x_display_get(), ee->engine.x.mask, - GCForeground, - &gcv); - XFillRectangle(ecore_x_display_get(), ee->engine.x.mask, gc, - 0, 0, ee->w, ee->h); - XFreeGC(ecore_x_display_get(), gc); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - else - { - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - einfo->info.mask = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - } -#endif /* BUILD_ECORE_EVAS_XRENDER_X11 || BUILD_ECORE_EVAS_XRENDER_XCB */ + 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) - { - GC gc; - XGCValues gcv; - - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); - einfo->info.mask = ee->engine.x.mask; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - } - else - { - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - einfo->info.mask = 0; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - } - } + 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) { -# ifdef HAVE_ECORE_X_XCB - 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; -#else - XWindowAttributes att; -#endif /* ! HAVE_ECORE_X_XCB */ + Ecore_X_Window_Attributes att; + char *id = NULL; - if (((ee->alpha) && (alpha)) || ((!ee->alpha) && (!alpha))) - return; + if ((ee->alpha == alpha)) return; - if (!strcmp(ee->driver, "software_x11") || !strcmp(ee->driver, "software_xcb")) + if (!strcmp(ee->driver, "software_x11")) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -#else - Evas_Engine_Info_Software_X11 *einfo; - - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - if (!einfo) return; - - if (!ecore_x_composite_query()) return; - - ee->shaped = 0; - ee->alpha = alpha; - ecore_x_window_del(ee->engine.x.win); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->alpha) - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (!ee->engine.x.mask) - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); - } - else - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - - einfo->info.destination_alpha = alpha; + einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); + if (!einfo) return; -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - cookie_geom = xcb_get_geometry_unchecked(ecore_x_connection_get(), ee->engine.x.win); - cookie_attr = xcb_get_window_attributes_unchecked(ecore_x_connection_get(), ee->engine.x.win); - - 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); - 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; - free(reply_geom); - free(reply_attr); -# else - XGetWindowAttributes(ecore_x_display_get(), ee->engine.x.win, &att); - einfo->info.visual = att.visual; - einfo->info.colormap = att.colormap; - einfo->info.depth = att.depth; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - -// if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); -// ee->engine.x.mask = 0; - einfo->info.mask = ee->engine.x.mask; - einfo->info.drawable = ee->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->prop.borderless) - ecore_x_mwm_borderless_set(ee->engine.x.win, ee->prop.borderless); - if (ee->visible) ecore_x_window_show(ee->engine.x.win); - if (ee->prop.focused) ecore_x_window_focus(ee->engine.x.win); - if (ee->prop.title) - { - ecore_x_icccm_title_set(ee->engine.x.win, ee->prop.title); - ecore_x_netwm_name_set(ee->engine.x.win, ee->prop.title); - } -#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 || BUILD_ECORE_EVAS_SOFTWARE_XCB */ - } - else if (!strcmp(ee->driver, "xrender_x11") || !strcmp(ee->driver, "xrender_xcb")) - { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - Evas_Engine_Info_XRender_Xcb *einfo; - - einfo = (Evas_Engine_Info_XRender_Xcb *)evas_engine_info_get(ee->evas); -# else - Evas_Engine_Info_XRender_X11 *einfo; - - einfo = (Evas_Engine_Info_XRender_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - - if (!einfo) return; - if (!ecore_x_composite_query()) return; - - ee->shaped = 0; - ee->alpha = alpha; - ecore_x_window_del(ee->engine.x.win); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->alpha) - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (!ee->engine.x.mask) - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); - } - else - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } - - einfo->info.destination_alpha = alpha; - -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - cookie_attr = xcb_get_window_attributes_unchecked(ecore_x_connection_get(), ee->engine.x.win); - reply_attr = xcb_get_window_attributes_reply(ecore_x_connection_get(), cookie_attr, NULL); - - einfo->info.visual = reply_attr->visual; - free(reply_attr); -# else - XGetWindowAttributes(ecore_x_display_get(), ee->engine.x.win, &att); - einfo->info.visual = att.visual; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ + 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_del(ee->engine.x.mask); -// ee->engine.x.mask = 0; +// 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->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->prop.borderless) - ecore_x_mwm_borderless_set(ee->engine.x.win, ee->prop.borderless); - if (ee->visible) ecore_x_window_show(ee->engine.x.win); - if (ee->prop.focused) ecore_x_window_focus(ee->engine.x.win); - if (ee->prop.title) - { - ecore_x_icccm_title_set(ee->engine.x.win, ee->prop.title); - ecore_x_netwm_name_set(ee->engine.x.win, ee->prop.title); - } -#endif /* BUILD_ECORE_EVAS_XRENDER_X11 || BUILD_ECORE_EVAS_XRENDER_XCB */ + 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_del(ee->engine.x.win); - ecore_evases_hash = evas_hash_del(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->alpha) - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_argb_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (!ee->engine.x.mask) - ee->engine.x.mask = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, 1); - } - else - { - if (ee->prop.override) - ee->engine.x.win = ecore_x_window_override_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - else - ee->engine.x.win = ecore_x_window_new(ee->engine.x.win_root, ee->x, ee->y, ee->w, ee->h); - if (ee->engine.x.mask) ecore_x_pixmap_del(ee->engine.x.mask); - ee->engine.x.mask = 0; - ecore_x_window_shape_input_mask_set(ee->engine.x.win, 0); - } + 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; + 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_del(ee->engine.x.mask); -// ee->engine.x.mask = 0; +// 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->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - evas_damage_rectangle_add(ee->evas, 0, 0, ee->w, ee->h); - ecore_x_window_shape_mask_set(ee->engine.x.win, 0); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - if (ee->prop.borderless) - ecore_x_mwm_borderless_set(ee->engine.x.win, ee->prop.borderless); - if (ee->visible) ecore_x_window_show(ee->engine.x.win); - if (ee->prop.focused) ecore_x_window_focus(ee->engine.x.win); - if (ee->prop.title) - { - ecore_x_icccm_title_set(ee->engine.x.win, ee->prop.title); - ecore_x_netwm_name_set(ee->engine.x.win, ee->prop.title); - } + 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 */ } } -#endif /* BUILD_ECORE_EVAS_X11 */ -static void * -_ecore_evas_x_window_get(Ecore_Evas *ee) +static void +_ecore_evas_x_transparent_set(Ecore_Evas *ee, int transparent) { -#ifdef BUILD_ECORE_EVAS_X11 - return (void *) (long)ee->engine.x.win; -#else - return 0; -#endif /* BUILD_ECORE_EVAS_X11 */ + 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) @@ -2095,41 +2468,37 @@ _ecore_evas_x_show(Ecore_Evas *ee) ee->should_be_visible = 1; if (ee->prop.avoid_damage) _ecore_evas_x_render(ee); - ecore_x_window_show(ee->engine.x.win); + _ecore_evas_x_sync_set(ee); + ecore_x_window_show(ee->prop.window); if (ee->prop.fullscreen) - ecore_x_window_focus(ee->engine.x.win); + ecore_x_window_focus(ee->prop.window); } static void _ecore_evas_x_hide(Ecore_Evas *ee) { - ecore_x_window_hide(ee->engine.x.win); + 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) { - if (!ee->prop.fullscreen) - ecore_x_window_raise(ee->engine.x.win); - else - ecore_x_window_raise(ee->engine.x.win); + ecore_x_window_raise(ee->prop.window); } static void _ecore_evas_x_lower(Ecore_Evas *ee) { - if (!ee->prop.fullscreen) - ecore_x_window_lower(ee->engine.x.win); - else - ecore_x_window_lower(ee->engine.x.win); + 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->engine.x.win, 2, 0); + ee->prop.window, 2, 0); } static void @@ -2138,8 +2507,8 @@ _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->engine.x.win, ee->prop.title); - ecore_x_netwm_name_set(ee->engine.x.win, 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); } static void @@ -2149,9 +2518,9 @@ _ecore_evas_x_name_class_set(Ecore_Evas *ee, const char *n, const char *c) if (ee->prop.clas) free(ee->prop.clas); ee->prop.name = NULL; ee->prop.clas = NULL; - ee->prop.name = strdup(n); - ee->prop.clas = strdup(c); - ecore_x_icccm_name_class_set(ee->engine.x.win, ee->prop.name, ee->prop.clas); + 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 @@ -2199,20 +2568,29 @@ _ecore_evas_x_size_step_set(Ecore_Evas *ee, int w, int 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_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 == NULL) + 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->engine.x.win, 1); - return; + 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; @@ -2220,16 +2598,18 @@ _ecore_evas_x_object_cursor_set(Ecore_Evas *ee, Evas_Object *obj, int layer, int ee->prop.cursor.hot.x = hot_x; ee->prop.cursor.hot.y = hot_y; - ecore_x_window_cursor_show(ee->engine.x.win, 0); + 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); + 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); } /* @@ -2258,48 +2638,28 @@ _ecore_evas_x_layer_set(Ecore_Evas *ee, int layer) static void _ecore_evas_x_focus_set(Ecore_Evas *ee, int on __UNUSED__) { - ecore_x_window_focus(ee->engine.x.win); + ecore_x_window_focus(ee->prop.window); } static void _ecore_evas_x_iconified_set(Ecore_Evas *ee, int on) { -// if (((ee->prop.iconified) && (on)) || -// ((!ee->prop.iconified) && (!on))) return; - ee->prop.iconified = on; + if (ee->prop.iconified == on) return; + if (((ee->should_be_visible) && (!ee->visible)) || (!ee->visible)) + ee->prop.iconified = on; + _ecore_evas_x_hints_update(ee); if (on) - { - ecore_x_icccm_hints_set(ee->engine.x.win, - 1 /* accepts_focus */, - ECORE_X_WINDOW_STATE_HINT_ICONIC /* initial_state */, - 0 /* icon_pixmap */, - 0 /* icon_mask */, - 0 /* icon_window */, - 0 /* window_group */, - 0 /* is_urgent */); - ecore_x_icccm_iconic_request_send(ee->engine.x.win, ee->engine.x.win_root); - } - else - { - ecore_x_icccm_hints_set(ee->engine.x.win, - 1 /* accepts_focus */, - ECORE_X_WINDOW_STATE_HINT_NORMAL /* initial_state */, - 0 /* icon_pixmap */, - 0 /* icon_mask */, - 0 /* icon_window */, - 0 /* window_group */, - 0 /* is_urgent */); - ecore_evas_show(ee); - } + 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)) || - ((!ee->prop.borderless) && (!on))) return; + if (ee->prop.borderless == on) return; ee->prop.borderless = on; - ecore_x_mwm_borderless_set(ee->engine.x.win, ee->prop.borderless); + ecore_x_mwm_borderless_set(ee->prop.window, ee->prop.borderless); } /* FIXME: This function changes the initial state of the ee @@ -2307,42 +2667,29 @@ _ecore_evas_x_borderless_set(Ecore_Evas *ee, int on) static void _ecore_evas_x_withdrawn_set(Ecore_Evas *ee, int withdrawn) { - Ecore_X_Window_State_Hint hint; - - if ((ee->prop.withdrawn && withdrawn) || - (!ee->prop.withdrawn && !withdrawn)) return; - - ee->prop.withdrawn = withdrawn; + if (ee->prop.withdrawn == withdrawn) return; +// ee->prop.withdrawn = withdrawn; + _ecore_evas_x_hints_update(ee); if (withdrawn) - hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + ecore_evas_hide(ee); else - hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; - - ecore_x_icccm_hints_set(ee->engine.x.win, - 1 /* accepts_focus */, - hint /* initial_state */, - 0 /* icon_pixmap */, - 0 /* icon_mask */, - 0 /* icon_window */, - 0 /* window_group */, - 0 /* is_urgent */); + ecore_evas_show(ee); } static void _ecore_evas_x_sticky_set(Ecore_Evas *ee, int sticky) { - if ((ee->prop.sticky && sticky) || - (!ee->prop.sticky && !sticky)) return; + 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; +// ee->engine.x.state.sticky = sticky; if (ee->should_be_visible) - ecore_x_netwm_state_request_send(ee->engine.x.win, ee->engine.x.win_root, - ECORE_X_WINDOW_STATE_STICKY, -1, sticky); + 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); } @@ -2350,21 +2697,11 @@ _ecore_evas_x_sticky_set(Ecore_Evas *ee, int sticky) static void _ecore_evas_x_ignore_events_set(Ecore_Evas *ee, int ignore) { - if ((ee->ignore_events && ignore) || - (!ee->ignore_events && !ignore)) return; + if (ee->ignore_events == ignore) return; - if (ignore) - { - ee->ignore_events = 1; - if (ee->engine.x.win) - ecore_x_window_ignore_set(ee->engine.x.win, 1); - } - else - { - ee->ignore_events = 0; - if (ee->engine.x.win) - ecore_x_window_ignore_set(ee->engine.x.win, 0); - } + ee->ignore_events = ignore; + if (ee->prop.window) + ecore_x_window_ignore_set(ee->prop.window, ignore); } /* @@ -2374,40 +2711,27 @@ _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->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } -#endif - } - else if (!strcmp(ee->driver, "xrender_x11")) - { -#ifdef BUILD_ECORE_EVAS_XRENDER_X11 - Evas_Engine_Info_XRender_X11 *einfo; + Evas_Engine_Info_Software_X11 *einfo; - einfo = (Evas_Engine_Info_XRender_X11 *)evas_engine_info_get(ee->evas); - if (einfo) - { - einfo->info.drawable = ee->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)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, "gl_x11")) + 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->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } + 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 } } @@ -2416,141 +2740,297 @@ _ecore_evas_x_reinit_win(Ecore_Evas *ee) static void _ecore_evas_x_override_set(Ecore_Evas *ee, int on) { - if (((ee->prop.override) && (on)) || - ((!ee->prop.override) && (!on))) return; - ecore_x_window_hide(ee->engine.x.win); - ecore_x_window_override_set(ee->engine.x.win, on); - if (ee->visible) ecore_x_window_show(ee->engine.x.win); - if (ee->prop.focused) ecore_x_window_focus(ee->engine.x.win); + 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) || - (!ee->prop.fullscreen && !on)) return; + 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->engine.x.win, ee->engine.x.win_root, - ECORE_X_WINDOW_STATE_FULLSCREEN, -1, on); + 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, "gl_x11")) return; - if (!strcmp(ee->driver, "xrender_x11")) return; + if (!strcmp(ee->driver, "opengl_x11")) return; - if ((!strcmp(ee->driver, "software_x11")) || (!strcmp(ee->driver, "software_xcb"))) + if (!strcmp(ee->driver, "software_x11")) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; -# else - Evas_Engine_Info_Software_X11 *einfo; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ +#ifdef BUILD_ECORE_EVAS_SOFTWARE_X11 + Evas_Engine_Info_Software_X11 *einfo; - ee->prop.avoid_damage = on; -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -# else - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -# endif /* !BUILD_ECORE_EVAS_SOFTWARE_XCB */ - if (einfo) - { - if (ee->prop.avoid_damage) - { - ee->engine.x.pmap = ecore_x_pixmap_new(ee->engine.x.win, ee->w, ee->h, einfo->info.depth); - ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap); - einfo->info.drawable = ee->engine.x.pmap; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - 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->engine.x.win, ee->engine.x.pmap); - ecore_x_window_area_expose(ee->engine.x.win, 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->engine.x.win, ee->engine.x.pmap); - */ - } - } - else - { - if (ee->engine.x.pmap) ecore_x_pixmap_del(ee->engine.x.pmap); - if (ee->engine.x.gc) ecore_x_gc_del(ee->engine.x.gc); - if (ee->engine.x.using_bg_pixmap) - { - ecore_x_window_pixmap_set(ee->engine.x.win, 0); - ee->engine.x.using_bg_pixmap = 0; - ecore_x_window_area_expose(ee->engine.x.win, 0, 0, ee->w, ee->h); - } - ee->engine.x.pmap = 0; - ee->engine.x.gc = 0; - einfo->info.drawable = ee->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } - } -#endif /* BUILD_ECORE_EVAS_SOFTWARE_X11 || BUILD_ECORE_EVAS_SOFTWARE_XCB */ + 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->engine.x.win, ee->w, ee->h, 16); - ee->engine.x.gc = ecore_x_gc_new(ee->engine.x.pmap); - einfo->info.drawable = ee->engine.x.pmap; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - 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->engine.x.win, ee->engine.x.pmap); - */ - } - } - else - { - if (ee->engine.x.pmap) ecore_x_pixmap_del(ee->engine.x.pmap); - if (ee->engine.x.gc) ecore_x_gc_del(ee->engine.x.gc); - if (ee->engine.x.using_bg_pixmap) - { - ecore_x_window_pixmap_set(ee->engine.x.win, 0); - ee->engine.x.using_bg_pixmap = 0; - } - ee->engine.x.pmap = 0; - ee->engine.x.gc = 0; - einfo->info.drawable = ee->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } - } + 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 @@ -2559,20 +3039,20 @@ _ecore_evas_x_shutdown(void) _ecore_evas_init_count--; if (_ecore_evas_init_count == 0) { - int i; + unsigned int i; - while (ecore_evases) _ecore_evas_free(ecore_evases); - for (i = 0; i < 18; i++) - ecore_event_handler_del(ecore_evas_event_handlers[i]); - ecore_idle_enterer_del(ecore_evas_idle_enterer); - ecore_evas_idle_enterer = NULL; - if (_ecore_evas_fps_debug) _ecore_evas_fps_debug_shutdown(); + 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 const Ecore_Evas_Engine_Func _ecore_x_engine_func = +static Ecore_Evas_Engine_Func _ecore_x_engine_func = { _ecore_evas_x_free, NULL, @@ -2612,47 +3092,426 @@ static const Ecore_Evas_Engine_Func _ecore_x_engine_func = _ecore_evas_x_iconified_set, _ecore_evas_x_borderless_set, _ecore_evas_x_override_set, - NULL, + _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_window_get + _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 supress some round trips. + * 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 /** - * To be documented. - * - * FIXME: To be fixed. + * @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_software_x11_new(const char *disp_name, Ecore_X_Window parent, - int x, int y, int w, int h) +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) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - Evas_Engine_Info_Software_Xcb *einfo; -# else - Evas_Engine_Info_Software_X11 *einfo; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ Ecore_Evas *ee; - int argb = 0; int rmethod; - static int redraw_debug = -1; + char *id = NULL; -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - rmethod = evas_render_method_lookup("software_xcb"); -# else - rmethod = evas_render_method_lookup("software_x11"); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ + 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)); @@ -2660,15 +3519,20 @@ ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, 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; -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - ee->driver = "software_xcb"; -# else - ee->driver = "software_x11"; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ + 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; @@ -2677,6 +3541,10 @@ ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, 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; @@ -2687,323 +3555,247 @@ ecore_evas_software_x11_new(const char *disp_name, Ecore_X_Window parent, /* 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 (parent != 0) + + 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(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); + 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->engine.x.win = ecore_x_window_new(parent, x, y, w, h); - if (getenv("DESKTOP_STARTUP_ID")) + 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) { - ecore_x_netwm_startup_id_set(ee->engine.x.win, - 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="); + ERR("evas_engine_info_set() init engine '%s' failed.", ee->driver); + ecore_evas_free(ee); + return NULL; } -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - einfo = (Evas_Engine_Info_Software_Xcb *)evas_engine_info_get(ee->evas); -# else - einfo = (Evas_Engine_Info_Software_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - if (einfo) + if ((id = getenv("DESKTOP_STARTUP_ID"))) { -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - xcb_screen_iterator_t iter; - xcb_screen_t *screen; -# else - int screen; -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - /* FIXME: this is inefficient as its a round trip */ -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - 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); - } - } -# else - screen = DefaultScreen(ecore_x_display_get()); - 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]) - { - screen = i; - break; - } - } - } - free(roots); - } - } -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - - 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.conn = ecore_x_connection_get(); - einfo->info.screen = screen; -# else - einfo->info.display = ecore_x_display_get(); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - einfo->info.drawable = ee->engine.x.win; - if (argb) - { - /* FIXME: round trip */ -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - 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->engine.x.win); - cookie_attr = xcb_get_window_attributes_unchecked(ecore_x_connection_get(), ee->engine.x.win); + 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="); + } - 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 - XWindowAttributes at; - - if (XGetWindowAttributes(ecore_x_display_get(), ee->engine.x.win, - &at)) - { - einfo->info.visual = at.visual; - einfo->info.colormap = at.colormap; - einfo->info.depth = at.depth; - einfo->info.destination_alpha = 1; - } -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - } - else - { -# ifdef BUILD_ECORE_EVAS_SOFTWARE_XCB - xcb_screen_t *screen; + _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); - 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; -#else - einfo->info.visual = DefaultVisual(ecore_x_display_get(), screen); - einfo->info.colormap = DefaultColormap(ecore_x_display_get(), screen); - einfo->info.depth = DefaultDepth(ecore_x_display_get(), screen); -# endif /* ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ - einfo->info.destination_alpha = 0; - } - einfo->info.rotation = 0; - einfo->info.debug = redraw_debug; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } - 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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); 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; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_X11 && ! BUILD_ECORE_EVAS_SOFTWARE_XCB */ } - -/** - * To be documented. - * - * FIXME: To be fixed. - */ -EAPI Ecore_X_Window -ecore_evas_software_x11_window_get(Ecore_Evas *ee) +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__) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) - return (Ecore_X_Window) (long)_ecore_evas_x_window_get(ee); -#else - return 0; -#endif + return NULL; } +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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_software_x11_subwindow_get(Ecore_Evas *ee) +ecore_evas_gl_x11_window_get(const Ecore_Evas *ee) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) - return (Ecore_X_Window) (long)_ecore_evas_x_window_get(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 } +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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_software_x11_direct_resize_set(Ecore_Evas *ee, int on) +ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) 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; -#endif +EAPI void +ecore_evas_gl_x11_direct_resize_set(Ecore_Evas *ee __UNUSED__, Eina_Bool on __UNUSED__) +{ } +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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. */ -EAPI int -ecore_evas_software_x11_direct_resize_get(Ecore_Evas *ee) +#ifdef BUILD_ECORE_EVAS_OPENGL_X11 +EAPI Eina_Bool +ecore_evas_gl_x11_direct_resize_get(const Ecore_Evas *ee) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) 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 } +#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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_software_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +ecore_evas_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) { -#if defined (BUILD_ECORE_EVAS_SOFTWARE_X11) || defined (BUILD_ECORE_EVAS_SOFTWARE_XCB) - Ecore_X_Window *winp; + 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 */ - winp = malloc(sizeof(Ecore_X_Window)); - if (winp) +/** + * @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) { - *winp = win; - ee->engine.x.win_extra = evas_list_append(ee->engine.x.win_extra, winp); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(win), ee); + 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 -#endif +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__) +{ } /** - * To be documented. - * - * FIXME: To be fixed. + * @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_gl_x11_new(const char *disp_name, Ecore_X_Window parent, - int x, int y, int w, int h) +ecore_evas_software_x11_16_new(const char *disp_name, Ecore_X_Window parent, + int x, int y, int w, int h) { -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 -# ifdef HAVE_ECORE_X_XCB - Ecore_Evas *ee = NULL; -# else - Evas_Engine_Info_GL_X11 *einfo; + Evas_Engine_Info_Software_16_X11 *einfo; Ecore_Evas *ee; int rmethod; + static int redraw_debug = -1; - rmethod = evas_render_method_lookup("gl_x11"); + 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)); @@ -3015,7 +3807,7 @@ ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; - ee->driver = "gl_x11"; + ee->driver = "software_16_x11"; if (disp_name) ee->name = strdup(disp_name); if (w < 1) w = 1; @@ -3024,6 +3816,10 @@ ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, 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; @@ -3034,147 +3830,248 @@ ecore_evas_gl_x11_new(const char *disp_name, Ecore_X_Window parent, /* 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; - einfo = (Evas_Engine_Info_GL_X11 *)evas_engine_info_get(ee->evas); - if (einfo) + if (parent != 0) { - ee->engine.x.win = _ecore_evas_x_gl_window_new(ee, ee->engine.x.win_root, x, y, w, h, 0); - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); + /* 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->engine.x.win, - 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="); - } - 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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); -# endif /* HAVE_ECORE_X_XCB */ + 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 - disp_name = NULL; - parent = 0; - x = y = w = h = 0; +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_OPENGL_X11 */ } +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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_gl_x11_window_get(Ecore_Evas *ee) +ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 - return (Ecore_X_Window) _ecore_evas_x_window_get(ee); -#else - return 0; -#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ + if (!(!strcmp(ee->driver, "software_16_x11"))) return 0; + return (Ecore_X_Window) ecore_evas_window_get(ee); } - -/** - * To be documented. - * - * FIXME: To be fixed. - */ +#else EAPI Ecore_X_Window -ecore_evas_gl_x11_subwindow_get(Ecore_Evas *ee) +ecore_evas_software_x11_16_window_get(const Ecore_Evas *ee __UNUSED__) { -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 - return (Ecore_X_Window) _ecore_evas_x_window_get(ee); -#else return 0; -#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ } +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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_gl_x11_direct_resize_set(Ecore_Evas *ee, int on) +ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) { -#ifdef BUILD_ECORE_EVAS_OPENGL_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->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 - return; -#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ +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 */ /** - * To be documented. - * - * FIXME: To be fixed. + * @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. */ -EAPI int -ecore_evas_gl_x11_direct_resize_get(Ecore_Evas *ee) +#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 +EAPI Eina_Bool +ecore_evas_software_x11_16_direct_resize_get(const Ecore_Evas *ee) { -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 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_OPENGL_X11 */ } +#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; -/** - * To be documented. - * - * FIXME: To be fixed. - */ + 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_gl_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee __UNUSED__, Ecore_X_Window win __UNUSED__) { -#ifdef BUILD_ECORE_EVAS_OPENGL_X11 - ecore_evas_software_x11_extra_event_window_add(ee, win); -#endif /* ! BUILD_ECORE_EVAS_OPENGL_X11 */ } +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + /** - * To be documented. - * - * FIXME: To be fixed. + * @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_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, - int x, int y, int w, int h) +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_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - Evas_Engine_Info_XRender_Xcb *einfo; -# else - Evas_Engine_Info_XRender_X11 *einfo; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ +#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; -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - rmethod = evas_render_method_lookup("xrender_xcb"); -# else - rmethod = evas_render_method_lookup("xrender_x11"); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ + 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)); @@ -3186,11 +4083,7 @@ ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, ee->engine.func = (Ecore_Evas_Engine_Func *)&_ecore_x_engine_func; -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - ee->driver = "xrender_xcb"; -# else - ee->driver = "xrender_x11"; -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ + ee->driver = "software_8_x11"; if (disp_name) ee->name = strdup(disp_name); if (w < 1) w = 1; @@ -3199,6 +4092,10 @@ ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, 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; @@ -3209,440 +4106,565 @@ ecore_evas_xrender_x11_new(const char *disp_name, Ecore_X_Window parent, /* 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.win = ecore_x_window_new(parent, x, y, w, h); + // 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->engine.x.win, - 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="); + 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="); } -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB - einfo = (Evas_Engine_Info_XRender_Xcb *)evas_engine_info_get(ee->evas); -# else - einfo = (Evas_Engine_Info_XRender_X11 *)evas_engine_info_get(ee->evas); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ + einfo = (Evas_Engine_Info_Software_8_X11 *)evas_engine_info_get(ee->evas); if (einfo) { -# ifdef BUILD_ECORE_EVAS_XRENDER_XCB xcb_screen_iterator_t iter; - xcb_screen_t *screen; + xcb_screen_t *screen; - /* FIXME: this is inefficient as its a round trip */ - screen = ecore_x_default_screen_get(); + /* 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) - { + 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; + Ecore_X_Window *roots; + int num; + uint8_t i; - num = 0; + num = 0; cookie = xcb_get_geometry_unchecked(ecore_x_connection_get(), parent); - roots = ecore_x_window_root_list(&num); - if (roots) - { + 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; - } - } + 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); - } + } + free(roots); + } else { reply = xcb_get_geometry_reply(ecore_x_connection_get(), cookie, NULL); if (reply) free(reply); } - } - einfo->info.conn = ecore_x_connection_get(); - /* FIXME: uncomment that once the XCB render engine has that member */ -/* einfo->info.screen = screen; */ - einfo->info.visual = screen->root_visual; -# else - int screen; - - /* FIXME: this is inefficient as its a round trip */ - screen = DefaultScreen(ecore_x_display_get()); - 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]) - { - screen = i; - break; - } - } - } - free(roots); - } - } - einfo->info.display = ecore_x_display_get(); - einfo->info.visual = DefaultVisual(ecore_x_display_get(), screen); -# endif /* ! BUILD_ECORE_EVAS_XRENDER_XCB */ - einfo->info.drawable = ee->engine.x.win; - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } - 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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); + } + + 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; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(disp_name); + (void)(parent); + (void)(x); + (void)(y); + (void)(w); + (void)(h); +#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_8_X11 */ } /** - * To be documented. - * - * FIXME: To be fixed. + * @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_xrender_x11_window_get(Ecore_Evas *ee) +ecore_evas_software_x11_8_window_get(const Ecore_Evas *ee) { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) - return (Ecore_X_Window) _ecore_evas_x_window_get(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; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(ee); +#endif } /** - * To be documented. - * - * FIXME: To be fixed. + * @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_xrender_x11_subwindow_get(Ecore_Evas *ee) +ecore_evas_software_x11_8_subwindow_get(const Ecore_Evas *ee) { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) - return (Ecore_X_Window) _ecore_evas_x_window_get(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; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(ee); +#endif } /** - * To be documented. - * - * FIXME: To be fixed. + * @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_xrender_x11_direct_resize_set(Ecore_Evas *ee, int on) +ecore_evas_software_x11_8_direct_resize_set(Ecore_Evas *ee, Eina_Bool on) { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) +#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; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(ee); + (void)(on); +#endif } /** - * To be documented. - * - * FIXME: To be fixed. + * @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 int -ecore_evas_xrender_x11_direct_resize_get(Ecore_Evas *ee) +EAPI Eina_Bool +ecore_evas_software_x11_8_direct_resize_get(const Ecore_Evas *ee) { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) +#if defined (BUILD_ECORE_EVAS_SOFTWARE_8_X11) return ee->engine.x.direct_resize; #else return 0; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(ee); +#endif } /** - * To be documented. - * - * FIXME: To be fixed. + * @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_xrender_x11_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +ecore_evas_software_x11_8_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) { -#if defined (BUILD_ECORE_EVAS_XRENDER_X11) || defined (BUILD_ECORE_EVAS_XRENDER_XCB) - ecore_evas_software_x11_extra_event_window_add(ee, 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; -#endif /* ! BUILD_ECORE_EVAS_XRENDER_X11 && ! BUILD_ECORE_EVAS_XRENDER_XCB */ + (void)(ee); + (void)(win); +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ -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 void +ecore_evas_x11_leader_set(Ecore_Evas *ee, Ecore_X_Window win) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - Evas_Engine_Info_Software_16_X11 *einfo; - Ecore_Evas *ee; - int argb = 0; - 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); +#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 +} - if (w < 1) w = 1; - if (h < 1) h = 1; - ee->x = x; - ee->y = y; - ee->w = w; - ee->h = h; +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 +} - 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; +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 +} - /* 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); +#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; - ee->engine.x.win_root = parent; - if (parent != 0) + if (ee->rotation == 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); + 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 - ee->engine.x.win = ecore_x_window_new(parent, x, y, w, h); - if (getenv("DESKTOP_STARTUP_ID")) { - ecore_x_netwm_startup_id_set(ee->engine.x.win, - 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="); + return 0; } - einfo = (Evas_Engine_Info_Software_16_X11 *)evas_engine_info_get(ee->evas); - if (einfo) + 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)) { - int screen; - - screen = DefaultScreen(ecore_x_display_get()); - 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]) - { - screen = 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->engine.x.win; - - evas_engine_info_set(ee->evas, (Evas_Engine_Info *)einfo); - } - 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"); - - ecore_evases = _ecore_list2_prepend(ecore_evases, ee); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(ee->engine.x.win), ee); - return ee; + 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 NULL; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ -EAPI Ecore_X_Window -ecore_evas_software_x11_16_window_get(Ecore_Evas *ee) +EAPI void +ecore_evas_x11_shape_input_rectangle_add(Ecore_Evas *ee, int x, int y, int w, int h) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - return (Ecore_X_Window) _ecore_evas_x_window_get(ee); +#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 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ -EAPI Ecore_X_Window -ecore_evas_software_x11_16_subwindow_get(Ecore_Evas *ee) +EAPI void +ecore_evas_x11_shape_input_rectangle_subtract(Ecore_Evas *ee, int x, int y, int w, int h) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - return (Ecore_X_Window) _ecore_evas_x_window_get(ee); +#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 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + return; + ee = NULL; + x = 0; + y = 0; + w = 0; + h = 0; +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ EAPI void -ecore_evas_software_x11_16_direct_resize_set(Ecore_Evas *ee, int on) +ecore_evas_x11_shape_input_empty(Ecore_Evas *ee) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - ee->engine.x.direct_resize = on; - if (ee->prop.avoid_damage) +#ifdef BUILD_ECORE_EVAS_X11 + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - 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); - */ - } + 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; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + ee = NULL; +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ -EAPI int -ecore_evas_software_x11_16_direct_resize_get(Ecore_Evas *ee) +EAPI void +ecore_evas_x11_shape_input_reset(Ecore_Evas *ee) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - return ee->engine.x.direct_resize; +#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 0; -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + return; + ee = NULL; +#endif } -/** - * To be documented. - * - * FIXME: To be fixed. - */ EAPI void -ecore_evas_software_x11_16_extra_event_window_add(Ecore_Evas *ee, Ecore_X_Window win) +ecore_evas_x11_shape_input_apply(Ecore_Evas *ee) { -#if BUILD_ECORE_EVAS_SOFTWARE_16_X11 - Ecore_X_Window *winp; - - winp = malloc(sizeof(Ecore_X_Window)); - if (winp) +#ifdef BUILD_ECORE_EVAS_X11 + if (!ECORE_MAGIC_CHECK(ee, ECORE_MAGIC_EVAS)) { - *winp = win; - ee->engine.x.win_extra = evas_list_append(ee->engine.x.win_extra, winp); - ecore_evases_hash = evas_hash_add(ecore_evases_hash, _ecore_evas_x_winid_str_get(win), ee); + 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 -#endif /* ! BUILD_ECORE_EVAS_SOFTWARE_16_X11 */ + return; + ee = NULL; +#endif } diff --git a/src/lib/ecore_fb/Ecore_Fb.h b/src/lib/ecore_fb/Ecore_Fb.h index 5374817..069cccd 100644 --- a/src/lib/ecore_fb/Ecore_Fb.h +++ b/src/lib/ecore_fb/Ecore_Fb.h @@ -1,37 +1,27 @@ #ifndef _ECORE_FB_H #define _ECORE_FB_H +#include + #ifdef EAPI -#undef 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 + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) # else # define EAPI # endif +#else +# define EAPI #endif -/** - * @file - * @brief Ecore frame buffer system functions. - */ - /* FIXME: * maybe a new module? * - code to get battery info * - code to get thermal info - * ecore evas fb isnt good enough for weird things, like multiple fb's, same happens here. + * 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 @@ -43,101 +33,66 @@ extern "C" { #endif -typedef struct _Ecore_Fb_Input_Device Ecore_Fb_Input_Device; /* an input device handler */ +/** + * @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; -/* device capabilities */ +/** + * @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 + ECORE_FB_INPUT_DEVICE_CAP_RELATIVE = 0x00000001, + ECORE_FB_INPUT_DEVICE_CAP_ABSOLUTE = 0x00000002, + ECORE_FB_INPUT_DEVICE_CAP_KEYS_OR_BUTTONS = 0x00000004 }; -typedef enum _Ecore_Fb_Input_Device_Cap Ecore_Fb_Input_Device_Cap; -EAPI extern int ECORE_FB_EVENT_KEY_DOWN; /**< FB Key Down event */ -EAPI extern int ECORE_FB_EVENT_KEY_UP; /**< FB Key Up event */ -EAPI extern int ECORE_FB_EVENT_MOUSE_BUTTON_DOWN; /**< FB Mouse Down event */ -EAPI extern int ECORE_FB_EVENT_MOUSE_BUTTON_UP; /**< FB Mouse Up event */ -EAPI extern int ECORE_FB_EVENT_MOUSE_MOVE; /**< FB Mouse Move event */ -EAPI extern int ECORE_FB_EVENT_MOUSE_WHEEL; /**< FB Mouse Wheel event */ - -typedef struct _Ecore_Fb_Event_Key_Down Ecore_Fb_Event_Key_Down; /**< FB Key Down event */ -typedef struct _Ecore_Fb_Event_Key_Up Ecore_Fb_Event_Key_Up; /**< FB Key Up event */ -typedef struct _Ecore_Fb_Event_Mouse_Button_Down Ecore_Fb_Event_Mouse_Button_Down; /**< FB Mouse Down event */ -typedef struct _Ecore_Fb_Event_Mouse_Button_Up Ecore_Fb_Event_Mouse_Button_Up; /**< FB Mouse Up event */ -typedef struct _Ecore_Fb_Event_Mouse_Move Ecore_Fb_Event_Mouse_Move; /**< FB Mouse Move event */ -typedef struct _Ecore_Fb_Event_Mouse_Wheel Ecore_Fb_Event_Mouse_Wheel; /**< FB Mouse Wheel event */ - -struct _Ecore_Fb_Event_Key_Down /** FB Key Down event */ -{ - Ecore_Fb_Input_Device *dev; /**< The device associated with the event */ - char *keyname; /**< The name of the key that was pressed */ - char *keysymbol; /**< The logical symbol of the key that was pressed */ - char *key_compose; /**< The UTF-8 string conversion if any */ -}; - -struct _Ecore_Fb_Event_Key_Up /** FB Key Up event */ -{ - Ecore_Fb_Input_Device *dev; /**< The device associated with the event */ - char *keyname; /**< The name of the key that was released */ - char *keysymbol; /**< The logical symbol of the key that was pressed */ - char *key_compose; /**< The UTF-8 string conversion if any */ -}; - -struct _Ecore_Fb_Event_Mouse_Button_Down /** FB Mouse Down event */ -{ - Ecore_Fb_Input_Device *dev; /**< The device associated with the 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 */ -}; - -struct _Ecore_Fb_Event_Mouse_Button_Up /** FB Mouse Up event */ -{ - Ecore_Fb_Input_Device *dev; /**< The device associated with the 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 */ -}; - -struct _Ecore_Fb_Event_Mouse_Move /** FB Mouse Move event */ -{ - Ecore_Fb_Input_Device *dev; /**< The device associated with the event */ - int x; /**< Mouse co-ordinates where the mouse cursor moved to */ - int y; /**< Mouse co-ordinates where the mouse cursor moved to */ -}; - -struct _Ecore_Fb_Event_Mouse_Wheel /** FB Mouse Wheel event */ -{ - Ecore_Fb_Input_Device *dev; - int x,y; - int direction; /* 0 = vertical, 1 = horizontal */ - int wheel; /* value 1 (left/up), -1 (right/down) */ -}; +/** + * @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); +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, int 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 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); - +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 diff --git a/src/lib/ecore_fb/Makefile.am b/src/lib/ecore_fb/Makefile.am index 5cc71bb..9129fec 100644 --- a/src/lib/ecore_fb/Makefile.am +++ b/src/lib/ecore_fb/Makefile.am @@ -2,37 +2,33 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_builddir)/src/lib/ecore +-I$(top_builddir)/src/lib/ecore \ +-I$(top_srcdir)/src/lib/ecore_input \ +@TSLIB_CFLAGS@ \ +@EINA_CFLAGS@ -if BUILD_ECORE_FB lib_LTLIBRARIES = libecore_fb.la -include_HEADERS = \ -Ecore_Fb.h +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 \ -ecore_fb_private.h +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 +@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@ - -libecore_fb_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la - -endif +libecore_fb_la_LDFLAGS = -version-info @version_info@ @release_info@ EXTRA_DIST = \ -Ecore_Fb.h \ -ecore_fb.c \ 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 index a695dda..5b2b84b 100644 --- a/src/lib/ecore_fb/ecore_fb.c +++ b/src/lib/ecore_fb/ecore_fb.c @@ -1,75 +1,99 @@ +#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); -EAPI int ECORE_FB_EVENT_KEY_DOWN = 0; -EAPI int ECORE_FB_EVENT_KEY_UP = 0; -EAPI int ECORE_FB_EVENT_MOUSE_BUTTON_DOWN = 0; -EAPI int ECORE_FB_EVENT_MOUSE_BUTTON_UP = 0; -EAPI int ECORE_FB_EVENT_MOUSE_MOVE = 0; -EAPI int ECORE_FB_EVENT_MOUSE_WHEEL = 0; - static int _ecore_fb_init_count = 0; static int _ecore_fb_console_w = 0; static int _ecore_fb_console_h = 0; -static double _ecore_fb_double_click_time = 0.25; - - /** - * @defgroup Ecore_FB_Library_Group Framebuffer Library Functions + * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. * - * Functions used to set up and shut down the Ecore_Framebuffer functions. + * @{ */ +static sighandler_t oldhand = NULL; + +static void +nosigint(int val __UNUSED__) +{ +} + /** - * Sets up the Ecore_Fb 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_FB_Library_Group + * @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) - { - if(!ecore_fb_vt_init()) return 0; - ECORE_FB_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_FB_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_FB_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_FB_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_FB_EVENT_MOUSE_MOVE = ecore_event_type_new(); - ECORE_FB_EVENT_MOUSE_WHEEL = ecore_event_type_new(); - _ecore_fb_size_get(&_ecore_fb_console_w, &_ecore_fb_console_h); - } - return ++_ecore_fb_init_count; + 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; } /** - * Shuts down the Ecore_Fb library. - * @return @c The number of times the system has been initialised without - * being shut down. - * @ingroup Ecore_FB_Library_Group + * @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) -{ - _ecore_fb_init_count--; - if(!_ecore_fb_init_count) - { - ecore_fb_vt_shutdown(); - return 0; - } - return _ecore_fb_init_count; +{ + 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; } /** - * Retrieves the width and height of the current frame buffer in pixels. + * @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) @@ -83,21 +107,23 @@ _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) - { - if (w) *w = 0; - if (h) *h = 0; - return; - } + goto exit; + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) == -1) - { - if (w) *w = 0; - if (h) *h = 0; - return; - } + goto err_ioctl; + + *w = fb_var.xres; + *h = fb_var.yres; + +err_ioctl: close(fb); - if (w) *w = fb_var.xres; - if (h) *h = fb_var.yres; +exit: + return; } + +/** + * @} + */ diff --git a/src/lib/ecore_fb/ecore_fb_kbd.c b/src/lib/ecore_fb/ecore_fb_kbd.c index 0cc1186..f9cdc3d 100644 --- a/src/lib/ecore_fb/ecore_fb_kbd.c +++ b/src/lib/ecore_fb/ecore_fb_kbd.c @@ -1,7 +1,7 @@ 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 * 6] = +static const char *_ecore_fb_kbd_syms[128 * 7] = { #include "ecore_fb_keytable.h" }; @@ -9,128 +9,128 @@ static const char *_ecore_fb_kbd_syms[128 * 6] = static const char *_ecore_fb_btn_syms[128] = { "0x00", - "Escape", - "F1", - "F2", - "F3", - "F4", - "Up", + "Escape", + "F1", + "F2", + "F3", + "F4", + "Up", "Right", - "Left", - "Down", - "Return", - "0x1b", - "0x1c", - "0x1d", + "Left", + "Down", + "Return", + "0x1b", + "0x1c", + "0x1d", "0x1e", "0x1f", - "0x20", - "0x21", - "0x22", - "0x23", - "0x24", - "0x25", - "0x26", + "0x20", + "0x21", + "0x22", + "0x23", + "0x24", + "0x25", + "0x26", "0x27", - "0x28", - "0x29", + "0x28", + "0x29", "0x2a", "0x2b", "0x2c", "0x2d", - "0x2e", - "0x2f", - "0x30", - "0x31", - "0x32", - "0x33", - "0x34", - "0x35", - "0x36", + "0x2e", + "0x2f", + "0x30", + "0x31", + "0x32", + "0x33", + "0x34", + "0x35", + "0x36", "0x37", - "0x38", - "0x39", + "0x38", + "0x39", "0x3a", "0x3b", "0x3c", "0x3d", - "0x3e", - "0x3f", - "0x40", - "0x41", - "0x42", - "0x43", - "0x44", - "0x45", - "0x46", + "0x3e", + "0x3f", + "0x40", + "0x41", + "0x42", + "0x43", + "0x44", + "0x45", + "0x46", "0x47", - "0x48", - "0x49", + "0x48", + "0x49", "0x4a", "0x4b", "0x4c", "0x4d", - "0x4e", - "0x4f", - "0x50", - "0x51", - "0x52", - "0x53", - "0x54", - "0x55", - "0x56", + "0x4e", + "0x4f", + "0x50", + "0x51", + "0x52", + "0x53", + "0x54", + "0x55", + "0x56", "0x57", - "0x58", - "0x59", + "0x58", + "0x59", "0x5a", "0x5b", "0x5c", "0x5d", - "0x5e", - "0x5f", - "0x60", - "0x61", - "0x62", - "0x63", - "0x64", - "0x65", - "0x66", + "0x5e", + "0x5f", + "0x60", + "0x61", + "0x62", + "0x63", + "0x64", + "0x65", + "0x66", "0x67", - "0x68", - "0x69", + "0x68", + "0x69", "0x6a", "0x6b", "0x6c", "0x6d", - "0x6e", - "0x6f", - "0x70", - "0x71", - "0x72", - "0x73", - "0x74", - "0x75", - "0x76", + "0x6e", + "0x6f", + "0x70", + "0x71", + "0x72", + "0x73", + "0x74", + "0x75", + "0x76", "0x77", - "0x78", - "0x79", + "0x78", + "0x79", "0x7a", "0x7b", "0x7c", "0x7d", - "0x7e", + "0x7e", "0x7f" }; -static int _ecore_fb_kbd_fd = 0; +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 int _ecore_fb_kbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_fb_kbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); -static void +static void _ecore_fb_event_free_key_down(void *data __UNUSED__, void *ev) { Ecore_Fb_Event_Key_Up *e; @@ -145,7 +145,7 @@ 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); @@ -153,139 +153,160 @@ _ecore_fb_event_free_key_up(void *data __UNUSED__, void *ev) free(e); } -static int +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 1; - if (v < 1) return 1; - 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) * 6]); - e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 6) + add]); - e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 6) + 3 + add]); - } - else - e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]); - if (!e->keyname) - { - free(e); - goto retry; - } - ecore_event_add(ECORE_FB_EVENT_KEY_DOWN, e, _ecore_fb_event_free_key_down, 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++; - 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 ((vt_switch >= 0) && - (_ecore_fb_ctrl) && - (_ecore_fb_alt)) - _ecore_fb_vt_switch(vt_switch); - } - 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) * 6]); - e->keysymbol = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 6) + add]); - e->key_compose = strdup(_ecore_fb_kbd_syms[((buf & 0x7f) * 6) + 3 + add]); - } - else - e->keyname = strdup(_ecore_fb_btn_syms[buf & 0x7f]); - if (!e->keyname) - { - free(e); - goto retry; - } - 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: - ; + 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 1; + 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); + ECORE_FD_READ, + _ecore_fb_kbd_fd_handler, NULL, + NULL, NULL); if(!_ecore_fb_kbd_fd_handler_handle) return 0; return 1; } @@ -293,10 +314,10 @@ ecore_fb_kbd_init(void) 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); - if (_ecore_fb_kbd_fd_handler_handle) - ecore_main_fd_handler_del(_ecore_fb_kbd_fd_handler_handle); - _ecore_fb_kbd_fd = 0; + _ecore_fb_kbd_fd = -1; _ecore_fb_kbd_fd_handler_handle = NULL; _ecore_fb_ctrl = 0; _ecore_fb_lock = 0; diff --git a/src/lib/ecore_fb/ecore_fb_keytable.h b/src/lib/ecore_fb/ecore_fb_keytable.h index ff03497..70bf6b9 100644 --- a/src/lib/ecore_fb/ecore_fb_keytable.h +++ b/src/lib/ecore_fb/ecore_fb_keytable.h @@ -1,129 +1,129 @@ /* this table was taken from ecore_fb, is the default en layout */ - "0x00", "0x00", "0x00", /**/"", "", "",/***/ - "Escape", "Escape", "Escape", /**/"", "", "",/***/ - "1", "exclam", "1", /**/"1", "!", "1",/***/ - "2", "at", "2", /**/"2", "@", "2",/***/ - "3", "numbersign", "3", /**/"3", "#", "3",/***/ - "4", "dollar", "4", /**/"4", "$", "4",/***/ - "5", "percent", "5", /**/"5", "%", "5",/***/ - "6", "asciicircumm", "6", /**/"6", "^", "6",/***/ - "7", "ampersand", "7", /**/"7", "&", "7",/***/ - "8", "asterik", "8", /**/"8", "*", "8",/***/ - "9", "parenleft", "9", /**/"9", "(", "9",/***/ - "0", "parenright", "0", /**/"0", ")", "0",/***/ - "minus", "underscore", "minus", /**/"-", "_", "-",/***/ - "equal", "plus", "equal", /**/"=", "+", "=",/***/ - "BackSpace", "BackSpace", "BackSpace", /**/"\010","\010","\010",/***/ - "Tab", "ISO_Left_Tab", "Tab", /**/"\011","", "\011",/***/ - "q", "Q", "Q", /**/"q", "Q", "Q",/***/ - "w", "W", "W", /**/"w", "W", "W",/***/ - "e", "E", "E", /**/"e", "E", "E",/***/ - "r", "R", "R", /**/"r", "R", "R",/***/ - "t", "T", "T", /**/"t", "T", "T",/***/ - "y", "Y", "Y", /**/"y", "Y", "Y",/***/ - "u", "U", "U", /**/"u", "U", "U",/***/ - "i", "I", "I", /**/"i", "I", "I",/***/ - "o", "O", "O", /**/"o", "O", "O",/***/ - "p", "P", "P", /**/"p", "P", "P",/***/ - "bracketleft", "braceleft", "bracketleft", /**/"[", "{", "[",/***/ - "bracketright", "braceright", "bracketright", /**/"]", "}", "]",/***/ - "Return", "Return", "Return", /**/"\015","\015","\015",/***/ - "Control_L", "Control_L", "Control_L", /**/"", "", "",/***/ - "a", "A", "A", /**/"a", "A", "A",/***/ - "s", "S", "S", /**/"s", "S", "S",/***/ - "d", "D", "D", /**/"d", "D", "D",/***/ - "f", "F", "F", /**/"f", "F", "F",/***/ - "g", "G", "G", /**/"g", "G", "G",/***/ - "h", "h", "H", /**/"h", "H", "H",/***/ - "j", "J", "J", /**/"j", "J", "J",/***/ - "k", "K", "K", /**/"k", "K", "K",/***/ - "l", "L", "L", /**/"l", "L", "L",/***/ - "semicolon", "colon", "semicolon", /**/";", ":", ";",/***/ - "apostrophe", "quotedbl", "apostrophe", /**/"'", "\"", "'",/***/ - "grave", "asciitilde", "grave", /**/"`", "~", "`",/***/ - "Shift_L", "Shift_L", "Shift_L", /**/"", "", "",/***/ - "backslash", "bar", "backslash", /**/"\\", "|", "\\",/***/ - "z", "Z", "Z", /**/"z", "Z", "Z",/***/ - "x", "X", "X", /**/"x", "X", "X",/***/ - "c", "C", "C", /**/"c", "C", "C",/***/ - "v", "V", "V", /**/"v", "V", "V",/***/ - "b", "B", "B", /**/"b", "B", "B",/***/ - "n", "N", "N", /**/"n", "N", "N",/***/ - "m", "M", "M", /**/"m", "M", "M",/***/ - "comma", "less", "comma", /**/",", "<", ",",/***/ - "period", "greater", "period", /**/".", ">", ".",/***/ - "slash", "question", "slash", /**/"/", "?", "/",/***/ - "Shift_R", "Shift_R", "Shift_R", /**/"", "", "",/***/ - "KP_Multiply", "KP_Multiply", "KP_Multiply", /**/"", "*", "",/***/ - "Alt_L", "Alt_L", "Alt_L", /**/"", "", "",/***/ - "space", "space", "space", /**/" ", " ", " ",/***/ - "Caps_Lock", "Caps_Lock", "Caps_Lock", /**/"", "", "",/***/ - "F1", "F1", "F1", /**/"", "", "",/***/ - "F2", "F2", "F2", /**/"", "", "",/***/ - "F3", "F3", "F3", /**/"", "", "",/***/ - "F4", "F4", "F4", /**/"", "", "",/***/ - "F5", "F5", "F5", /**/"", "", "",/***/ - "F6", "F6", "F6", /**/"", "", "",/***/ - "F7", "F7", "F7", /**/"", "", "",/***/ - "F8", "F8", "F8", /**/"", "", "",/***/ - "F9", "F9", "F9", /**/"", "", "",/***/ - "F10", "F10", "F10", /**/"", "", "",/***/ - "Num_Lock", "Num_Lock", "Num_Lock", /**/"", "", "",/***/ - "Scroll_Lock", "Scroll_Lock", "Scroll_Lock", /**/"", "", "",/***/ - "KP_Home", "KP_7", "KP_Home", /**/"", "7", "",/***/ - "KP_Up", "KP_8", "KP_Up", /**/"", "8", "",/***/ - "KP_Prior", "KP_9", "KP_Prior", /**/"", "9", "",/***/ - "KP_Subtract", "KP_Subtract", "KP_Subtract", /**/"", "", "",/***/ - "KP_Left", "KP_4", "KP_Left", /**/"", "4", "",/***/ - "KP_Begin", "KP_5", "KP_Begin", /**/"", "5", "",/***/ - "KP_Right", "KP_6", "KP_Right", /**/"", "6", "",/***/ - "KP_Add", "KP_Add", "KP_Add", /**/"", "", "",/***/ - "KP_End", "KP_1", "KP_End", /**/"", "1", "",/***/ - "KP_Down", "KP_2", "KP_Down", /**/"", "2", "",/***/ - "KP_Next", "KP_3", "KP_Next", /**/"", "3", "",/***/ - "KP_Insert", "KP_0", "KP_Insert", /**/"", "0", "",/***/ - "KP_Delete", "KP_Decimal", "KP_Delete", /**/"", ".", "",/***/ - "0x54", "0x54", "0x54", /**/"", "", "",/***/ - "0x55", "0x55", "0x55", /**/"", "", "",/***/ - "0x56", "0x56", "0x56", /**/"", "", "",/***/ - "F11", "F11", "F11", /**/"", "", "",/***/ - "F12", "F12", "F12", /**/"", "", "",/***/ - "0x59", "0x59", "0x59", /**/"", "", "",/***/ - "0x5a", "0x5a", "0x5a", /**/"", "", "",/***/ - "0x5b", "0x5b", "0x5b", /**/"", "", "",/***/ - "0x5c", "0x5c", "0x5c", /**/"", "", "",/***/ - "0x5d", "0x5d", "0x5d", /**/"", "", "",/***/ - "0x5e", "0x5e", "0x5e", /**/"", "", "",/***/ - "0x5f", "0x5f", "0x5f", /**/"", "", "",/***/ - "KP_Enter", "KP_Enter", "KP_Enter", /**/"", "", "",/***/ - "Control_R", "Control_R", "Control_R", /**/"", "", "",/***/ - "KP_Divide", "KP_Divide", "KP_Divide", /**/"", "", "",/***/ - "Print", "Print", "Print", /**/"", "", "",/***/ - "Alt_R", "Alt_R", "Alt_R", /**/"", "", "",/***/ - "0x65", "0x65", "0x65", /**/"", "", "",/***/ - "Home", "Home", "Home", /**/"", "", "",/***/ - "Up", "Up", "Up", /**/"", "", "",/***/ - "Prior", "Prior", "Prior", /**/"", "", "",/***/ - "Left", "Left", "Left", /**/"", "", "",/***/ - "Right", "Right", "Right", /**/"", "", "",/***/ - "End", "End", "End", /**/"", "", "",/***/ - "Down", "Down", "Down", /**/"", "", "",/***/ - "Next", "Next", "Next", /**/"", "", "",/***/ - "Insert", "Insert", "Insert", /**/"", "", "",/***/ - "Delete", "Delete", "Delete", /**/"\177","\177","\177",/***/ - "0x70", "0x70", "0x70", /**/"", "", "",/***/ - "0x71", "0x71", "0x71", /**/"", "", "",/***/ - "0x72", "0x72", "0x72", /**/"", "", "",/***/ - "0x73", "0x73", "0x73", /**/"", "", "",/***/ - "0x74", "0x74", "0x74", /**/"", "", "",/***/ - "0x75", "0x75", "0x75", /**/"", "", "",/***/ - "0x76", "0x76", "0x76", /**/"", "", "",/***/ - "Pause", "Pause", "Pause", /**/"", "", "",/***/ - "0x78", "0x78", "0x78", /**/"", "", "",/***/ - "0x79", "0x79", "0x79", /**/"", "", "",/***/ - "0x7a", "0x7a", "0x7a", /**/"", "", "",/***/ - "0x7b", "0x7b", "0x7b", /**/"", "", "",/***/ - "0x7c", "0x7c", "0x7c", /**/"", "", "",/***/ - "Super_L", "Super_L", "Super_L", /**/"", "", "",/***/ - "Super_R", "Super_R", "Super_R", /**/"", "", "",/***/ - "0x7f", "0x7f", "0x7f", /**/"", "", "" /***/ + "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 index cc1d591..78a3e5b 100644 --- a/src/lib/ecore_fb/ecore_fb_li.c +++ b/src/lib/ecore_fb/ecore_fb_li.c @@ -1,11 +1,17 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + #include "Ecore_Fb.h" #include "ecore_fb_private.h" #define CLICK_THRESHOLD_DEFAULT 0.25 -static Ecore_List *_ecore_fb_li_devices = NULL; +static Eina_List *_ecore_fb_li_devices = NULL; -static const char *_ecore_fb_li_kbd_syms[128 * 6] = +static const char *_ecore_fb_li_kbd_syms[128 * 7] = { #include "ecore_fb_keytable.h" }; @@ -18,503 +24,699 @@ static const char *_ecore_fb_li_kbd_syms[128 * 6] = * 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 + * - bigeasy */ -extern int long_has_neither_32_not_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_event_free_key_down(void *data, void *ev) +extern int long_has_neither_32_nor_64_bits(void); +static inline int +test_bit(int bit, unsigned long *array) { - - 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_li_event_free_key_up(void *data, 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); + 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) - { - /* check the key table */ - if(iev->value) - { - int offset = 0; - Ecore_Fb_Event_Key_Down *ev; - - ev = calloc(1, sizeof(Ecore_Fb_Event_Key_Down)); - if(dev->keyboard.shift) offset = 1; - else if(dev->keyboard.lock) offset = 2; - ev->keyname = strdup(_ecore_fb_li_kbd_syms[iev->code * 6]); - - ev->keysymbol = strdup(_ecore_fb_li_kbd_syms[(iev->code * 6) + offset]); - ev->key_compose = strdup(_ecore_fb_li_kbd_syms[(iev->code * 6) + 3 + offset]); - ev->dev = dev; - ecore_event_add(ECORE_FB_EVENT_KEY_DOWN, ev, _ecore_fb_li_event_free_key_down, NULL); - /* its a repeated key, dont increment */ - if(iev->value == 2) - return; - if (!strcmp(ev->keyname, "Control_L")) - dev->keyboard.ctrl++; - else if (!strcmp(ev->keyname, "Control_R")) - dev->keyboard.ctrl++; - else if (!strcmp(ev->keyname, "Alt_L")) - dev->keyboard.alt++; - else if (!strcmp(ev->keyname, "Alt_R")) - dev->keyboard.alt++; - else if (!strcmp(ev->keyname, "Shift_L")) - dev->keyboard.shift++; - else if (!strcmp(ev->keyname, "Shift_R")) - dev->keyboard.shift++; - else if (!strcmp(ev->keyname, "Caps_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 - { - int offset = 0; - Ecore_Fb_Event_Key_Up *ev; - - ev = calloc(1, sizeof(Ecore_Fb_Event_Key_Up)); - if(dev->keyboard.shift) offset = 1; - else if(dev->keyboard.lock) offset = 2; - ev->keyname = strdup(_ecore_fb_li_kbd_syms[iev->code * 6]); - - ev->keysymbol = strdup(_ecore_fb_li_kbd_syms[(iev->code * 6) + offset]); - ev->key_compose = strdup(_ecore_fb_li_kbd_syms[(iev->code * 6) + 3 + offset]); - ev->dev = dev; - ecore_event_add(ECORE_FB_EVENT_KEY_UP, ev, _ecore_fb_li_event_free_key_up, NULL); - if (!strcmp(ev->keyname, "Control_L")) - dev->keyboard.ctrl--; - else if (!strcmp(ev->keyname, "Control_R")) - dev->keyboard.ctrl--; - else if (!strcmp(ev->keyname, "Alt_L")) - dev->keyboard.alt--; - else if (!strcmp(ev->keyname, "Alt_R")) - dev->keyboard.alt--; - else if (!strcmp(ev->keyname, "Shift_L")) - dev->keyboard.shift--; - else if (!strcmp(ev->keyname, "Shift_R")) - dev->keyboard.shift--; - else if (!strcmp(ev->keyname, "Caps_Lock")) - dev->keyboard.lock--; - 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; - } - } - /* check for mouse button events */ - else if(iev->code >= BTN_MOUSE && iev->code < BTN_JOYSTICK) - { - int button; - - button = ((iev->code & 0x00F) + 1); - if(iev->value) - { - Ecore_Fb_Event_Mouse_Button_Down *ev; - double current; - - ev = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Button_Down)); - ev->dev = dev; - ev->button = button; - ev->x = dev->mouse.x; - ev->y = dev->mouse.y; - - current = ecore_time_get(); - if((current - dev->mouse.prev) <= dev->mouse.threshold) - { - ev->double_click = 1; - } - if((current - dev->mouse.last) <= (2 * dev->mouse.threshold)) - { - ev->triple_click = 1; - /* reset */ - dev->mouse.prev = 0; - dev->mouse.last = 0; - current = 0; - } - else - { - /* update values */ - dev->mouse.last = dev->mouse.prev; - dev->mouse.prev = current; - } - ecore_event_add(ECORE_FB_EVENT_MOUSE_BUTTON_DOWN, ev, NULL ,NULL); - } - else - { - Ecore_Fb_Event_Mouse_Button_Up *ev; - - ev = calloc(1,sizeof(Ecore_Fb_Event_Mouse_Button_Up)); - ev->dev = dev; - ev->button = button; - ev->x = dev->mouse.x; - ev->y = dev->mouse.y; - - ecore_event_add(ECORE_FB_EVENT_MOUSE_BUTTON_UP, ev, NULL ,NULL); - } - } + 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_Fb_Event_Mouse_Move *ev; - 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; - } - ev = calloc(1,sizeof(Ecore_Fb_Event_Mouse_Move)); - ev->x = dev->mouse.x; - ev->y = dev->mouse.y; - ev->dev = dev; - - ecore_event_add(ECORE_FB_EVENT_MOUSE_MOVE,ev,NULL,NULL); - break; - } - case REL_WHEEL: - case REL_HWHEEL: - { - Ecore_Fb_Event_Mouse_Wheel *ev; - ev = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Wheel)); - - ev->x = dev->mouse.x; - ev->y = dev->mouse.y; - if(iev->code == REL_HWHEEL) - ev->direction = 1; - ev->wheel = iev->value; - ev->dev = dev; - ecore_event_add(ECORE_FB_EVENT_MOUSE_WHEEL, ev, NULL, NULL); - break; - } - default: - break; - } + 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) { - if(!dev->listen) - return; - switch(iev->code) - { - case ABS_X: - case ABS_Y: - { - Ecore_Fb_Event_Mouse_Move *ev; - if((iev->code == ABS_X) && (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; - } - else if((iev->code == ABS_Y) && (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; - } - ev = calloc(1,sizeof(Ecore_Fb_Event_Mouse_Move)); - ev->x = dev->mouse.x; - ev->y = dev->mouse.y; - ev->dev = dev; - - ecore_event_add(ECORE_FB_EVENT_MOUSE_MOVE, ev, NULL, NULL); - break; - } - case ABS_PRESSURE: - /* TODO emulate a button press */ - break; - } + 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; + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); + } + 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 int -_ecore_fb_li_device_fd_callback(void *data, Ecore_Fd_Handler *fdh) +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)); - // printf("[ecore_fb_li_device:fd_callback] received %d data\n", len); - for(i = 0; i < len/sizeof(ev[0]); i++) - { - switch(ev[i].type) - { - 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 1; + 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; } -/* - * Starts getting events from the input device +/** + * @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, int listen) +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; + 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) +# define EV_CNT (EV_MAX+1) #endif -/* - * Opens an input device +/** + * @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(!_ecore_fb_li_devices) - _ecore_fb_li_devices = ecore_list_new(); - - 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_list_append(_ecore_fb_li_devices, device); - return device; - - error_caps: - close(fd); - error_open: - free(device); - return NULL; - + 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) { - /* close the fd */ - close(dev->fd); - /* remove the element from the list */ - if(ecore_list_goto(_ecore_fb_li_devices, dev)) - ecore_list_remove(_ecore_fb_li_devices); - free(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); } -/* - * If the device is a relative input device, - * we must set a width and height for it. If its - * absolute set the ioctl correctly, if not, unsupported - * device +/** + * @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; + 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; + 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; + 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; + 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; + 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 index 2d09809..797f863 100644 --- a/src/lib/ecore_fb/ecore_fb_private.h +++ b/src/lib/ecore_fb/ecore_fb_private.h @@ -1,11 +1,13 @@ #ifndef _ECORE_FB_PRIVATE_H #define _ECORE_FB_PRIVATE_H -#include "ecore_private.h" #include "Ecore.h" -#include "Ecore_Data.h" +#include "ecore_private.h" +#include "Ecore_Input.h" #include +#include +#include #include #include #include @@ -19,8 +21,8 @@ #define kernel_ulong_t unsigned long #define BITS_PER_LONG 32 #include - #undef kernel_ulong_t <-added - #undef BITS_PER_LONG <-added + #undef kernel_ulong_t + #undef BITS_PER_LONG #else #include #endif @@ -29,43 +31,53 @@ #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; - /* absolute axis */ - int min_w, min_h; - double rel_w, rel_h; - - } mouse; - struct - { - int shift; - int ctrl; - int alt; - int lock; - } keyboard; + 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); diff --git a/src/lib/ecore_fb/ecore_fb_ps2.c b/src/lib/ecore_fb/ecore_fb_ps2.c index 3a062da..fdff3a8 100644 --- a/src/lib/ecore_fb/ecore_fb_ps2.c +++ b/src/lib/ecore_fb/ecore_fb_ps2.c @@ -10,7 +10,7 @@ struct _Ecore_Fb_Ps2_Event 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 int _ecore_fb_ps2_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); +static Eina_Bool _ecore_fb_ps2_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); int ecore_fb_ps2_init(void) @@ -18,19 +18,19 @@ 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; + 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; + return 0; } void @@ -40,7 +40,7 @@ ecore_fb_ps2_shutdown(void) _ecore_fb_ps2_fd = 0; } -static int +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; @@ -50,101 +50,139 @@ _ecore_fb_ps2_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __U do { - int x, y, button, i; - int num; - char *ptr; - double t; - 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 1; - _ecore_fb_ps2_event_byte_count += v; - if (v < num) return 1; - t = ecore_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_Fb_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Move)); - if (!e) goto retry; - e->x = x; - e->y = y; - ecore_event_add(ECORE_FB_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_Fb_Event_Mouse_Button_Down *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Button_Down)); - if (!e) goto retry; - e->x = x; - e->y = y; - e->button = 1; - if ((t - last_time) <= _ecore_fb_double_click_time) - e->double_click = 1; - if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time)) - { - did_triple = 1; - e->triple_click = 1; - } - ecore_event_add(ECORE_FB_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); - } - else if ((!(button & mask)) && ((prev_button & mask))) - { - /* UP: mouse was down, but is not now */ - Ecore_Fb_Event_Mouse_Button_Up *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Button_Up)); - if (!e) goto retry; - e->x = x; - e->y = y; - e->button = 1; - ecore_event_add(ECORE_FB_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; + 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 1; + return EINA_TRUE; } /** * @defgroup Ecore_FB_Click_Group Framebuffer Double Click Functions @@ -154,7 +192,7 @@ _ecore_fb_ps2_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __U /** * 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. diff --git a/src/lib/ecore_fb/ecore_fb_ts.c b/src/lib/ecore_fb/ecore_fb_ts.c index 5d4f589..a33bb36 100644 --- a/src/lib/ecore_fb/ecore_fb_ts.c +++ b/src/lib/ecore_fb/ecore_fb_ts.c @@ -1,11 +1,15 @@ -#include "Ecore_Fb.h" -#include "ecore_fb_private.h" -#include "config.h" +#ifdef HAVE_CONFIG_H +# include +#endif + #ifdef HAVE_TSLIB -#include -#include +# 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; @@ -18,7 +22,7 @@ struct _Ecore_Fb_Ts_Event unsigned short pressure; unsigned short x; unsigned short y; - unsigned short _unused; + unsigned short _unused; }; struct _Ecore_Fb_Ts_Calibrate @@ -56,8 +60,8 @@ struct _Ecore_Fb_Ts_Flite unsigned char brightness; }; -static int _ecore_fb_ts_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_fb_ts_fd = 0; +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; @@ -70,54 +74,52 @@ 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) { - int prev_flags; #ifdef HAVE_TSLIB char *tslib_tsdevice = NULL; - if ( ( tslib_tsdevice = getenv("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; - } + { + 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; - } + { + 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; - } - } + { + 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) { - prev_flags = fcntl(_ecore_fb_ts_fd, F_GETFL); - fcntl(_ecore_fb_ts_fd, F_SETFL, prev_flags | O_NONBLOCK); - _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; + _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; } @@ -125,11 +127,24 @@ ecore_fb_ts_init(void) EAPI void ecore_fb_ts_shutdown(void) { - if (_ecore_fb_ts_fd >= 0) close(_ecore_fb_ts_fd); if (_ecore_fb_ts_fd_handler_handle) - ecore_main_fd_handler_del(_ecore_fb_ts_fd_handler_handle); - _ecore_fb_ts_fd = 0; + 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; } /** @@ -137,8 +152,8 @@ ecore_fb_ts_shutdown(void) * * Functions that calibrate the screen. */ - - + + /** * Calibrates the touschreen using the given parameters. * @param xscale X scaling, where 256 = 1.0 @@ -152,7 +167,7 @@ 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; @@ -161,9 +176,8 @@ ecore_fb_touch_screen_calibrate_set(int xscale, int xtrans, int yscale, int ytra 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; - + _ecore_fb_ts_cal = cal; + _ecore_fb_ts_apply_cal = 1; } } @@ -181,16 +195,15 @@ 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; - + if (ioctl(_ecore_fb_ts_fd, TS_GET_CAL, (void *)&cal)) + _ecore_fb_ts_cal = cal; } else - cal = _ecore_fb_ts_cal; + cal = _ecore_fb_ts_cal; if (xscale) *xscale = cal.xscale; if (xtrans) *xtrans = cal.xtrans; if (yscale) *yscale = cal.yscale; @@ -198,112 +211,150 @@ ecore_fb_touch_screen_calibrate_get(int *xscale, int *xtrans, int *yscale, int * if (xyswap) *xyswap = cal.xyswap; } -static int +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; - int did_triple = 0; + 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 */ - t = ecore_time_get(); + 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 - /* add event to queue */ - /* always add a move event */ - if ((pressure) || (prev_pressure)) - { - /* MOVE: mouse is down and was */ - Ecore_Fb_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Move)); - if (!e) goto retry; - e->x = x; - e->y = y; - ecore_event_add(ECORE_FB_EVENT_MOUSE_MOVE, e, NULL, NULL); - } - if ((pressure) && (!prev_pressure)) - { - /* DOWN: mouse is down, but was not now */ - Ecore_Fb_Event_Mouse_Button_Down *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Button_Down)); - if (!e) goto retry; - e->x = x; - e->y = y; - e->button = 1; - if ((t - last_time) <= _ecore_fb_double_click_time) - e->double_click = 1; - if ((t - last_last_time) <= (2 * _ecore_fb_double_click_time)) - { - did_triple = 1; - e->triple_click = 1; - } - ecore_event_add(ECORE_FB_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); - } - else if ((!pressure) && (prev_pressure)) - { - /* UP: mouse was down, but is not now */ - Ecore_Fb_Event_Mouse_Button_Up *e; - - e = calloc(1, sizeof(Ecore_Fb_Event_Mouse_Button_Up)); - if (!e) goto retry; - e->x = prev_x; - e->y = prev_y; - e->button = 1; - ecore_event_add(ECORE_FB_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); - } + 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; + { + 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 index 9831ef3..09e3f37 100644 --- a/src/lib/ecore_fb/ecore_fb_vt.c +++ b/src/lib/ecore_fb/ecore_fb_vt.c @@ -1,17 +1,21 @@ +#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 = 0; -static int _ecore_fb_vt_tty_fd = 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 int _ecore_fb_signal_usr_handler(void *data, int type, void *ev); +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; @@ -25,198 +29,216 @@ static void *_ecore_fb_func_fb_gain_data = NULL; /* FIXME what is the filter for? */ static Ecore_Event_Filter *_ecore_fb_filter_handler = NULL; -static void *_ecore_fb_event_filter_start(void *data); -static int _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); - /* 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 int +static Eina_Bool _ecore_fb_signal_usr_handler(void *data __UNUSED__, int type __UNUSED__, void *ev) { + Ecore_Event_Signal_User *e; - 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; + 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); + 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]; - 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] cant open tty %d\n", _ecore_fb_vt_current_vt); - return 0; - } - close(_ecore_fb_vt_tty0_fd); - _ecore_fb_vt_tty0_fd = 0; - /* 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] cant set the mode to KD_GRAPHICS"); - close(_ecore_fb_vt_tty_fd); - 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] cant set the tty mode"); - close(_ecore_fb_vt_tty_fd); - 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 does? */ - _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); - 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); - return 0; - } - /* FIXME assign the fb to the tty in case isnt setup */ - return 1; + 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] cant 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] cant 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] cant 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] cant 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; + 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 != 0) - { - 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 = 0; - } - - 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; + /* 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; } /** - * To be documented. + * @addtogroup Ecore_FB_Group Ecore_FB - Frame buffer convenience functions. + * + * @{ + */ + +/** + * @brief Set a callback called when a virtual terminal is gained. * - * FIXME: To be fixed. - * @todo Documentation: Find out what this does. + * @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) @@ -226,57 +248,75 @@ ecore_fb_callback_gain_set(void (*func) (void *data), void *data) } /** - * To be documented. + * @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. * - * FIXME: To be fixed. - * @todo Documentation: Find out what this does. + * 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 int +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 1; - if (type == ECORE_FB_EVENT_MOUSE_MOVE) + if (!filter_data) return EINA_TRUE; + if (type == ECORE_EVENT_MOUSE_MOVE) { - if ((filter_data->last_event_type) == ECORE_FB_EVENT_MOUSE_MOVE) - { - filter_data->last_event_type = type; - return 0; - } + 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 1; + 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 index 03c2355..30f3bd7 100644 --- a/src/lib/ecore_file/Ecore_File.h +++ b/src/lib/ecore_file/Ecore_File.h @@ -1,17 +1,13 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef ECORE_FILE_H #define ECORE_FILE_H -#include - /* * TODO: * - More events, move/rename of directory file */ +#include + #ifdef EAPI # undef EAPI #endif @@ -47,74 +43,145 @@ extern "C" { #endif - typedef struct _Ecore_File_Monitor Ecore_File_Monitor; - typedef struct _Ecore_File_Monitor_Event Ecore_File_Monitor_Event; - - typedef enum - { - ECORE_FILE_EVENT_NONE, - ECORE_FILE_EVENT_CREATED_FILE, - ECORE_FILE_EVENT_CREATED_DIRECTORY, - ECORE_FILE_EVENT_DELETED_FILE, - ECORE_FILE_EVENT_DELETED_DIRECTORY, - ECORE_FILE_EVENT_DELETED_SELF, - ECORE_FILE_EVENT_MODIFIED - } Ecore_File_Event; - - - 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 int ecore_file_exists (const char *file); - EAPI int ecore_file_is_dir (const char *file); - EAPI int ecore_file_mkdir (const char *dir); - EAPI int ecore_file_rmdir (const char *dir); - EAPI int ecore_file_recursive_rm (const char *dir); - EAPI int ecore_file_mkpath (const char *path); - EAPI int ecore_file_cp (const char *src, const char *dst); - EAPI int ecore_file_mv (const char *src, const char *dst); - EAPI int ecore_file_symlink (const char *src, const char *dest); - EAPI char *ecore_file_realpath (const char *file); - EAPI int ecore_file_unlink (const char *file); - EAPI const char *ecore_file_file_get (const char *path); - EAPI char *ecore_file_dir_get (const char *path); - - EAPI int ecore_file_can_read (const char *file); - EAPI int ecore_file_can_write (const char *file); - EAPI int ecore_file_can_exec (const char *file); - EAPI char *ecore_file_readlink (const char *link); - EAPI Ecore_List *ecore_file_ls (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); - - EAPI Ecore_File_Monitor * ecore_file_monitor_add(const char *path, - void (*func) (void *data, Ecore_File_Monitor *em, - Ecore_File_Event event, - const char *path), - 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); - - EAPI int ecore_file_path_dir_exists(const char *in_dir); - EAPI int ecore_file_app_installed(const char *exe); - EAPI Ecore_List *ecore_file_app_list(void); - - EAPI int ecore_file_download(const char *url, const char *dst, - void (*completion_cb)(void *data, - const char *file, - int status), - int (*progress_cb)(void *data, - const char *file, - long int dltotal, - long int dlnow, - long int ultotal, - long int ulnow), - void *data); - EAPI void ecore_file_download_abort_all(void); - EAPI int ecore_file_download_protocol_available(const char *protocol); +/** + * @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 } diff --git a/src/lib/ecore_file/Makefile.am b/src/lib/ecore_file/Makefile.am index a40d3ba..ab23ace 100644 --- a/src/lib/ecore_file/Makefile.am +++ b/src/lib/ecore_file/Makefile.am @@ -4,8 +4,11 @@ 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@ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ AM_CFLAGS = @WIN32_CFLAGS@ @@ -13,16 +16,15 @@ if BUILD_ECORE_CON lib_ecore_con_la = $(top_builddir)/src/lib/ecore_con/libecore_con.la endif -if BUILD_ECORE_FILE - lib_LTLIBRARIES = libecore_file.la -include_HEADERS = Ecore_File.h +includes_HEADERS = Ecore_File.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_file_la_SOURCES = \ ecore_file.c \ -ecore_file_private.h \ 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 @@ -30,17 +32,10 @@ ecore_file_download.c libecore_file_la_LIBADD = \ $(top_builddir)/src/lib/ecore/libecore.la \ $(lib_ecore_con_la) \ -@EVIL_LIBS@ - -libecore_file_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +@EVIL_LIBS@ \ +@EINA_LIBS@ -endif +libecore_file_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ -EXTRA_DIST = \ -ecore_file.c \ -ecore_file_private.h \ -ecore_file_monitor.c \ -ecore_file_monitor_inotify.c \ -ecore_file_monitor_poll.c \ -ecore_file_path.c +EXTRA_DIST = ecore_file_private.h diff --git a/src/lib/ecore_file/ecore_file.c b/src/lib/ecore_file/ecore_file.c index 10b9d58..c59bf80 100644 --- a/src/lib/ecore_file/ecore_file.c +++ b/src/lib/ecore_file/ecore_file.c @@ -1,13 +1,18 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif -#ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 +#include +#include +#include + +#ifndef _MSC_VER +# include +# include +#endif + +#ifdef _WIN32 +# include #endif #ifdef HAVE_FEATURES_H @@ -16,61 +21,115 @@ #include #include -#include "ecore_file_private.h" +#ifdef HAVE_ATFILE_SOURCE +# include +#endif +#include "ecore_file_private.h" -static int init = 0; +int _ecore_file_log_dom = -1; +static int _ecore_file_init_count = 0; /* externally accessible functions */ + /** - * Initialize Ecore_File and the services it will use. Call this function - * once before you use any of the ecore file functions. - * @return Return the number howoften ecore_file_init() was call succesfully; - * 0 if it failed. + * @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 (++init != 1) return 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 error; - if (!ecore_file_path_init()) - goto error; + goto shutdown_ecore_file_path; + if (!ecore_file_download_init()) - goto error; - return init; + goto shutdown_ecore_file_monitor; + */ -error: + return _ecore_file_init_count; + /* + shutdown_ecore_file_monitor: ecore_file_monitor_shutdown(); + shutdown_ecore_file_path: ecore_file_path_shutdown(); - ecore_file_download_shutdown(); - return --init; + return --_ecore_file_init_count; + */ } /** - * Shutdown the Ecore_File - * @return returns the number of libraries that still uses Ecore_File + * @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 (--init != 0) return init; + if (--_ecore_file_init_count != 0) + return _ecore_file_init_count; + ecore_file_download_shutdown(); ecore_file_monitor_shutdown(); ecore_file_path_shutdown(); - ecore_file_download_shutdown(); - return init; + eina_log_domain_unregister(_ecore_file_log_dom); + _ecore_file_log_dom = -1; + + ecore_shutdown(); + + return _ecore_file_init_count; } /** - * Get the time of the last modification to the give file - * @param file The name of the file - * @return Return the time of the last data modification, if an error should - * occur it will return 0 + * @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) @@ -82,9 +141,13 @@ ecore_file_mod_time(const char *file) } /** - * Get the size of the given file - * @param file The name of the file - * @return The size of the file in byte + * @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) @@ -96,190 +159,400 @@ ecore_file_size(const char *file) } /** - * Check if file exists - * @param file The name of the file - * @return 1 if file exists on local filesystem, 0 otherwise + * @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 int +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 0; - return 1; + if (stat(file, &st) < 0 && strcmp(file, "/")) return EINA_FALSE; + return EINA_TRUE; } /** - * Check if file is a directory - * @param file The name of the file - * @return 1 if file exist and is a directory, 0 otherwise + * @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 int +EAPI Eina_Bool ecore_file_is_dir(const char *file) { struct stat st; - if (stat(file, &st) < 0) return 0; - if (S_ISDIR(st.st_mode)) return 1; - return 0; + 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; /** - * Create a new directory + * @brief Create a new directory. + * * @param dir The name of the directory to create - * @return 1 on successfull creation, 0 on failure + * @return @c EINA_TRUE on successful creation, @c EINA_FALSE otherwise. * - * The directory is created with the mode: S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH + * 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 int +EAPI Eina_Bool ecore_file_mkdir(const char *dir) { - if (mkdir(dir, default_mode) < 0) return 0; - return 1; + if (mkdir(dir, default_mode) < 0) return EINA_FALSE; + return EINA_TRUE; } /** - * Delete the given dir - * @param dir The name of the directory to delete - * @return 1 on success, 0 on failure + * @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_rmdir(const char *dir) +ecore_file_mkdirs(const char **dirs) { - if (rmdir(dir) < 0) return 0; - return 1; + int i = 0; + + if (!dirs) return -1; + + for (; *dirs; dirs++) + if (ecore_file_mkdir(*dirs)) + i++; + return i; } /** - * Delete the given file - * @param file The name of the file to delete - * @return 1 on success, 0 on failure + * @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 0; - return 1; + if (unlink(file) < 0) return EINA_FALSE; + return EINA_TRUE; } /** - * Delete a directory and all its contents - * @param dir The name of the directory to delete - * @return 1 on success, 0 on failure + * @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. * - * If dir is a link only the link is removed + * This function removes @p file. It returns @c EINA_TRUE on success, + * @c EINA_FALSE otherwise. */ -EAPI int +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) { - DIR *dirp; - struct dirent *dp; - char path[PATH_MAX]; - char buf[PATH_MAX]; - struct stat st; - int ret; - - if (readlink(dir, buf, sizeof(buf)) > 0) - { - return ecore_file_unlink(dir); - } + Eina_Iterator *it; + char buf[PATH_MAX]; + struct stat st; + int ret; + + if (readlink(dir, buf, sizeof(buf) - 1) > 0) + return ecore_file_unlink(dir); ret = stat(dir, &st); if ((ret == 0) && (S_ISDIR(st.st_mode))) { - ret = 1; - if (stat(dir, &st) == -1) return 0; - dirp = opendir(dir); - if (dirp) - { - while ((dp = readdir(dirp))) - { - if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) - { - snprintf(path, PATH_MAX, "%s/%s", dir, dp->d_name); - if (!ecore_file_recursive_rm(path)) - ret = 0; - } - } - closedir(dirp); - } - if (!ecore_file_rmdir(dir)) ret = 0; - return ret; + 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 0; - return ecore_file_unlink(dir); + if (ret == -1) return EINA_FALSE; + return ecore_file_unlink(dir); } +} - return 1; +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; } /** - * Create a complete path + * @brief Create a complete path. + * * @param path The path to create - * @return 1 on success, 0 on failure + * @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 int +EAPI Eina_Bool ecore_file_mkpath(const char *path) { char ss[PATH_MAX]; - int i; + unsigned int i; - ss[0] = 0; - i = 0; - while (path[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 0; - ss[i] = path[i]; - ss[i + 1] = 0; - if (path[i] == '/') - { - ss[i] = 0; - if ((ecore_file_exists(ss)) && (!ecore_file_is_dir(ss))) return 0; - else if (!ecore_file_exists(ss)) ecore_file_mkdir(ss); - ss[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; + } } - if ((ecore_file_exists(ss)) && (!ecore_file_is_dir(ss))) return 0; - else if (!ecore_file_exists(ss)) ecore_file_mkdir(ss); - return 1; + ss[i] = '\0'; + return _ecore_file_mkpath_if_not_exists(ss); } /** - * Copy a file - * @param src The name of the source file - * @param dst The name of the destination file - * @return 1 on success, 0 on failure + * @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]; - char realpath2[PATH_MAX]; - size_t num; - int ret = 1; + 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 0; - if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return 0; + if (!realpath(src, realpath1)) return EINA_FALSE; + if (realpath(dst, realpath2) && !strcmp(realpath1, realpath2)) return EINA_FALSE; f1 = fopen(src, "rb"); - if (!f1) return 0; + if (!f1) return EINA_FALSE; f2 = fopen(dst, "wb"); if (!f2) { - fclose(f1); - return 0; + fclose(f1); + return EINA_FALSE; } while ((num = fread(buf, 1, sizeof(buf), f1)) > 0) { - if (fwrite(buf, 1, num, f2) != num) ret = 0; + if (fwrite(buf, 1, num, f2) != num) ret = EINA_FALSE; } fclose(f1); fclose(f2); @@ -287,59 +560,114 @@ ecore_file_cp(const char *src, const char *dst) } /** - * Move a file - * @param src The name of the source file - * @param dst The name of the destination file - * @return 1 on success, 0 on failure + * @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 int +EAPI Eina_Bool ecore_file_mv(const char *src, const char *dst) { - if (ecore_file_exists(dst)) return 0; + char buf[PATH_MAX]; + int fd; + if (rename(src, dst)) { - if (errno == EXDEV) - { - struct stat st; - - stat(src, &st); - if (S_ISREG(st.st_mode)) - { - ecore_file_cp(src, dst); - chmod(dst, st.st_mode); - ecore_file_unlink(src); - return 1; - } - } - return 0; + // 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; } - return 1; + +PASS: + return EINA_TRUE; + +FAIL: + return EINA_FALSE; } /** - * Create a symbolic link - * @param src The name of the file to link - * @param dest The name of link - * @return 1 on success, 0 on failure + * @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 int +EAPI Eina_Bool ecore_file_symlink(const char *src, const char *dest) { - if (!symlink(src, dest)) return 1; + if (!symlink(src, dest)) return EINA_TRUE; - return 0; + return EINA_FALSE; } /** - * Get the canonicalized absolute pathname - * @param file The file path - * @return The canonicalized absolute pathname; on failure it will return - * an empty string + * @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]; + char buf[PATH_MAX]; /* * Some implementations of realpath do not conform to the SUS. @@ -352,9 +680,13 @@ ecore_file_realpath(const char *file) } /** - * Get the filename from a give path - * @param path The complete path - * @return Only the file name + * 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) @@ -368,126 +700,152 @@ ecore_file_file_get(const char *path) } /** - * Get the directory where file reside - * @param file The name of the file - * @return The directory name + * @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]; + char *p; + char buf[PATH_MAX]; + if (!file) return NULL; strncpy(buf, file, PATH_MAX); - p = strrchr(buf, '/'); - if (!p) - { - return strdup(file); - } - - if (p == buf) return strdup("/"); - - *p = 0; - return strdup(buf); + buf[PATH_MAX - 1] = 0; + p = dirname(buf); + return strdup(p); } /** - * Check if file can be read - * @param file The name of the file - * @return 1 if the file is readable, 0 otherwise + * @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 int +EAPI Eina_Bool ecore_file_can_read(const char *file) { - if (!file) return 0; - if (!access(file, R_OK)) return 1; - return 0; + if (!file) return EINA_FALSE; + if (!access(file, R_OK)) return EINA_TRUE; + return EINA_FALSE; } /** - * Check if file can be written - * @param file The name of the file - * @return 1 if the file is writable, 0 otherwise + * @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 int +EAPI Eina_Bool ecore_file_can_write(const char *file) { - if (!file) return 0; - if (!access(file, W_OK)) return 1; - return 0; + if (!file) return EINA_FALSE; + if (!access(file, W_OK)) return EINA_TRUE; + return EINA_FALSE; } /** - * Check if file can be executed - * @param file The name of the file - * @return 1 if the file can be executed, 0 otherwise + * @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 int +EAPI Eina_Bool ecore_file_can_exec(const char *file) { - if (!file) return 0; - if (!access(file, X_OK)) return 1; - return 0; + if (!file) return EINA_FALSE; + if (!access(file, X_OK)) return EINA_TRUE; + return EINA_FALSE; } /** - * Get the path pointed by link - * @param link The name of the link - * @return The path pointed by link or NULL + * @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 *link) +ecore_file_readlink(const char *lnk) { - char buf[PATH_MAX]; - int count; + char buf[PATH_MAX]; + int count; - if ((count = readlink(link, buf, sizeof(buf))) < 0) return NULL; + if ((count = readlink(lnk, buf, sizeof(buf) - 1)) < 0) return NULL; buf[count] = 0; return strdup(buf); } /** - * Get the list of the files and directories in a given directory. 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 '..'. + * @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 Ecore_List containing all the files in the directory; + * @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 Ecore_List * +EAPI Eina_List * ecore_file_ls(const char *dir) { - char *f; - DIR *dirp; - struct dirent *dp; - Ecore_List *list; + Eina_File_Direct_Info *info; + Eina_Iterator *ls; + Eina_List *list = NULL; - dirp = opendir(dir); - if (!dirp) return NULL; + ls = eina_file_direct_ls(dir); + if (!ls) return NULL; - list = ecore_list_new(); - ecore_list_free_cb_set(list, free); - - while ((dp = readdir(dirp))) + EINA_ITERATOR_FOREACH(ls, info) { - if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) - { - f = strdup(dp->d_name); - ecore_list_append(list, f); - } + char *f; + + f = strdup(info->path + info->name_start); + list = eina_list_append(list, f); } - closedir(dirp); + eina_iterator_free(ls); - ecore_list_sort(list, ECORE_COMPARE_CB(strcoll), ECORE_SORT_MIN); + list = eina_list_sort(list, eina_list_count(list), EINA_COMPARE_CB(strcoll)); - ecore_list_first_goto(list); return list; } /** - * FIXME: To be documented. + * @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) @@ -500,65 +858,65 @@ ecore_file_app_exe_get(const char *app) p = (char *)app; restart: - while ((*p) && (isspace(*p))) p++; + 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(*p)) && (!((p > app) && (p[-1] != '\\')))) - break; - } - 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++; - } - } + 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; + if (exe) free(exe); + exe = malloc(exe2 - exe1 + 1); + if (!exe) return NULL; + pp = exe; } p = exe1; restart = 0; @@ -566,79 +924,85 @@ restart: 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 - { - /* techcincally 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(*p)) - { - if (restart) - goto restart; - else - break; - } - else - { - *pp = *p; - pp++; - } - } - 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; } /** - * Add the escape sequence ('\\') to the given filename - * @param filename The file name - * @return The file name with special characters escaped; if the length of the - * resulting string is longer than PATH_MAX it will return NULL + * @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) @@ -647,84 +1011,123 @@ ecore_file_escape_name(const char *filename) char *q; char buf[PATH_MAX]; + EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL); + 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++; + if ((q - buf) > (PATH_MAX - 6)) return NULL; + if ( + (*p == ' ') || (*p == '\\') || (*p == '\'') || + (*p == '\"') || (*p == ';') || (*p == '!') || + (*p == '#') || (*p == '$') || (*p == '%') || + (*p == '&') || (*p == '*') || (*p == '(') || + (*p == ')') || (*p == '[') || (*p == ']') || + (*p == '{') || (*p == '}') || (*p == '|') || + (*p == '<') || (*p == '>') || (*p == '?') + ) + { + *q = '\\'; + q++; + } + else if (*p == '\t') + { + *q = '\\'; + q++; + *q = '\\'; + q++; + *q = 't'; + q++; + p++; + continue; + } + else if (*p == '\n') + { + *q = '\\'; + q++; + *q = '\\'; + q++; + *q = 'n'; + q++; + p++; + continue; + } + + *q = *p; + q++; + p++; } *q = 0; return strdup(buf); } /** - * Remove the extension from a given path - * @param path The name of the file - * @return A newly allocated string with the extension stripped out or NULL on errors + * @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); - } + 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; - } + file = malloc(((p - path) + 1) * sizeof(char)); + if (file) + { + memcpy(file, path, (p - path)); + file[p - path] = 0; + } } return file; } /** - * Check if the given directory is empty. The '.' and '..' files will be ignored. - * @param dir The name of the directory to check - * @return 1 if directory is empty, 0 if it has at least one file or -1 in case of errors + * @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) { - DIR *dirp; - struct dirent *dp; + Eina_File_Direct_Info *info; + Eina_Iterator *it; - dirp = opendir(dir); - if (!dirp) return -1; + it = eina_file_direct_ls(dir); + if (!it) return -1; - while ((dp = readdir(dirp))) + EINA_ITERATOR_FOREACH(it, info) { - if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) - { - closedir(dirp); - return 0; - } + eina_iterator_free(it); + return 0; } - - closedir(dirp); + + 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 index e0472f0..03e593b 100644 --- a/src/lib/ecore_file/ecore_file_download.c +++ b/src/lib/ecore_file/ecore_file_download.c @@ -1,258 +1,357 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif -#include "Ecore_Con.h" +#include +#include +#include + +#ifdef BUILD_ECORE_CON +# include "Ecore_Con.h" +#endif + #include "ecore_file_private.h" -#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8 +#ifdef BUILD_ECORE_CON + +#define ECORE_MAGIC_FILE_DOWNLOAD_JOB 0xf7427cb8 +#define ECORE_FILE_DOWNLOAD_TIMEOUT 30 -typedef struct _Ecore_File_Download_Job Ecore_File_Download_Job; struct _Ecore_File_Download_Job { ECORE_MAGIC; - Ecore_Con_Url *url_con; - FILE *file; + Ecore_Con_Url *url_con; + FILE *file; - char *dst; + char *dst; - void (*completion_cb)(void *data, const char *file, int status); - - int (*progress_cb) (void *data, const char *file, - long int dltotal, long int dlnow, - long int ultotal, long int ulnow); + 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, - void (*completion_cb)(void *data, const char *file, int status), - int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow), - void *data); + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Eina_Hash *headers); -static int _ecore_file_download_url_complete_cb(void *data, int type, void *event); -static int _ecore_file_download_url_progress_cb(void *data, int type, void *event); +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 void _ecore_file_download_abort(Ecore_File_Download_Job *job); -static int init = 0; -static Ecore_Event_Handler *_url_complete_handler = NULL; -static Ecore_Event_Handler *_url_progress_download = NULL; -static Ecore_List *_job_list; +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 */ -EAPI int +int ecore_file_download_init(void) { -#ifndef _WIN32 - ecore_con_url_init(); - - if (init++ == 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 - } - if (!_job_list) +#ifdef BUILD_ECORE_CON + download_init++; + if (download_init > 1) return 1; + if (!ecore_con_init()) return 0; + if (!ecore_con_url_init()) { - _job_list = ecore_list_new(); - if (!_job_list) return 0; + 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; -#else - return 0; -#endif } -EAPI int +void ecore_file_download_shutdown(void) { -#ifndef _WIN32 - if (--init == 0) - { - 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; - if (_job_list) - ecore_list_destroy(_job_list); - _job_list = NULL; - } - - return ecore_con_url_shutdown(); -#else - return 0; -#endif +#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 */ } -EAPI void -ecore_file_download_abort_all(void) +#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) { - if (!ecore_list_empty_is(_job_list)) - { - Ecore_File_Download_Job *job; + Ecore_File_Download_Job *job = fdata; + ecore_con_url_additional_header_add(job->url_con, key, data); - while ((job = ecore_list_first_remove(_job_list))) - { - _ecore_file_download_abort(job); - } - } - ecore_list_clear(_job_list); + return EINA_TRUE; } +# endif +#endif -/** - * Download @p url to the given @p dst - * @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 - * @return 1 if the download start or 0 on failure - * - * You must provide the full url, including 'http://', 'ftp://' or 'file://'.\n - * If @p dst already exist it will not be overwritten and the function will fail.\n - * Ecore must be compiled with CURL to download using http and ftp protocols. - */ -EAPI int -ecore_file_download(const char *url, const char *dst, - void (*completion_cb)(void *data, const char *file, int status), - int (*progress_cb)(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow), - void *data) +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 + if (!url) + { + CRIT("Download URL is null"); + return EINA_FALSE; + } + char *dir = ecore_file_dir_get(dst); if (!ecore_file_is_dir(dir)) { - free(dir); - return 0; + ERR("%s is not a directory", dir); + free(dir); + return EINA_FALSE; } free(dir); - if (ecore_file_exists(dst)) return 0; + if (ecore_file_exists(dst)) + { + WRN("%s already exists", dst); + return EINA_FALSE; + } - /* FIXME: Add handlers for http and ftp! */ 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); + /* 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, "ftp://", 6))) +# 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); - if (job) - return 1; - else - return 0; + /* 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; } -#endif +# 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 0; + return EINA_FALSE; } -#ifndef HAVE_CURL - completion_cb = NULL; - progress_cb = NULL; - data = NULL; -#endif +#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); } /** - * Check if the given protocol is available - * @param protocol The protocol to check - * @return 1 if protocol is handled or 0 if not + * @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. * - * @p protocol can be 'http://', 'ftp://' or 'file://'.\n - * Ecore must be compiled with CURL to handle http and ftp protocols. + * 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 int +EAPI Eina_Bool ecore_file_download_protocol_available(const char *protocol) { - if (!strncmp(protocol, "file://", 7)) return 1; -#ifdef HAVE_CURL - else if (!strncmp(protocol, "http://", 7)) return 1; - else if (!strncmp(protocol, "ftp://", 6)) return 1; -#endif +#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 0; + return EINA_FALSE; } -#ifdef HAVE_CURL +#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; + const Ecore_File_Download_Job *job = data1; + const Ecore_Con_Url *url = data2; if (job->url_con == url) return 0; return -1; } -static int -_ecore_file_download_url_complete_cb(void *data, int type, void *event) +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; + Ecore_Con_Event_Url_Complete *ev = event; + Ecore_File_Download_Job *job; - job = ecore_list_find(_job_list, _ecore_file_download_url_compare_job, ev->url_con); - if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return 1; - - ecore_list_remove(_job_list); + 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->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, ev->status); - _ecore_file_download_abort(job); + _job_list = eina_list_remove(_job_list, job); + free(job->dst); + ecore_con_url_free(job->url_con); + free(job); - return 0; + return ECORE_CALLBACK_DONE; } -static int -_ecore_file_download_url_progress_cb(void *data, int type, void *event) +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; + Ecore_Con_Event_Url_Progress *ev = event; + Ecore_File_Download_Job *job; - job = ecore_list_find(_job_list, _ecore_file_download_url_compare_job, ev->url_con); - if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return 1; + 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) + (long int) ev->down.total, (long int) ev->down.now, + (long int) ev->up.total, (long int) ev->up.now) != 0) { - ecore_list_remove(_job_list); - _ecore_file_download_abort(job); + _job_list = eina_list_remove(_job_list, job); + fclose(job->file); + free(job->dst); + free(job); + + return ECORE_CALLBACK_PASS_ON; } - return 0; + return ECORE_CALLBACK_DONE; } Ecore_File_Download_Job * _ecore_file_download_curl(const char *url, const char *dst, - void (*completion_cb)(void *data, const char *file, - int status), - int (*progress_cb)(void *data, const char *file, - long int dltotal, long int dlnow, - long int ultotal, long int ulnow), - void *data) + Ecore_File_Download_Completion_Cb completion_cb, + Ecore_File_Download_Progress_Cb progress_cb, + void *data, + Eina_Hash *headers) { Ecore_File_Download_Job *job; @@ -264,17 +363,18 @@ _ecore_file_download_curl(const char *url, const char *dst, job->file = fopen(dst, "wb"); if (!job->file) { - free(job); - return NULL; + free(job); + return NULL; } job->url_con = ecore_con_url_new(url); if (!job->url_con) { - fclose(job->file); - free(job); - return NULL; + 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); @@ -282,21 +382,74 @@ _ecore_file_download_curl(const char *url, const char *dst, job->completion_cb = completion_cb; job->progress_cb = progress_cb; - ecore_list_append(_job_list, job); + _job_list = eina_list_append(_job_list, job); - ecore_con_url_send(job->url_con, NULL, 0, NULL); + 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 -static void -_ecore_file_download_abort(Ecore_File_Download_Job *job) +/** + * @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) { -#ifdef HAVE_CURL - ecore_con_url_destroy(job->url_con); -#endif + 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 index 32c1b20..8b07589 100644 --- a/src/lib/ecore_file/ecore_file_monitor.c +++ b/src/lib/ecore_file/ecore_file_monitor.c @@ -1,20 +1,17 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif #include "ecore_file_private.h" -static int init = 0; - 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 @@ -25,106 +22,159 @@ static Ecore_File_Monitor_Type monitor_type = ECORE_FILE_MONITOR_TYPE_NONE; int ecore_file_monitor_init(void) { - if (++init != 1) return init; - #ifdef HAVE_INOTIFY monitor_type = ECORE_FILE_MONITOR_TYPE_INOTIFY; if (ecore_file_monitor_inotify_init()) - return 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 init; + return 1; #endif monitor_type = ECORE_FILE_MONITOR_TYPE_NONE; - return --init; + return 0; } -int +void ecore_file_monitor_shutdown(void) { - if (--init != 0) return init; - switch (monitor_type) { case ECORE_FILE_MONITOR_TYPE_NONE: - break; + break; #ifdef HAVE_INOTIFY case ECORE_FILE_MONITOR_TYPE_INOTIFY: - ecore_file_monitor_inotify_shutdown(); - break; + 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; + ecore_file_monitor_poll_shutdown(); + break; #endif } - return init; } /** - * Monitor a path using inotify 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 + * @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, - void (*func) (void *data, Ecore_File_Monitor *em, - Ecore_File_Event event, - const char *path), - void *data) +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; + return NULL; #ifdef HAVE_INOTIFY case ECORE_FILE_MONITOR_TYPE_INOTIFY: - return ecore_file_monitor_inotify_add(path, func, data); + 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); + return ecore_file_monitor_poll_add(path, func, data); #endif } return NULL; } /** - * Stop monitoring a path - * @param em The Ecore_File_Monitor to stop + * @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; + break; #ifdef HAVE_INOTIFY case ECORE_FILE_MONITOR_TYPE_INOTIFY: - ecore_file_monitor_inotify_del(em); - break; + 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; + ecore_file_monitor_poll_del(em); + break; #endif } } /** - * Get the monitored path - * @param em The Ecore_File_Monitor to query - * @return The path that is monitored by @p em + * @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 index 513ee2c..30226d3 100644 --- a/src/lib/ecore_file/ecore_file_monitor_inotify.c +++ b/src/lib/ecore_file/ecore_file_monitor_inotify.c @@ -1,11 +1,13 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif +#include +#include +#include +#include +#include + #include "ecore_file_private.h" /* @@ -15,6 +17,7 @@ * 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 @@ -44,9 +47,10 @@ struct _Ecore_File_Monitor_Inotify }; static Ecore_Fd_Handler *_fdh = NULL; -static Ecore_List2 *_monitors = NULL; +static Ecore_File_Monitor *_monitors = NULL; +static pid_t _inotify_fd_pid = -1; -static int _ecore_file_monitor_inotify_handler(void *data, Ecore_Fd_Handler *fdh); +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); @@ -64,13 +68,14 @@ ecore_file_monitor_inotify_init(void) return 0; _fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _ecore_file_monitor_inotify_handler, - NULL, NULL, NULL); + NULL, NULL, NULL); if (!_fdh) { - close(fd); - return 0; + close(fd); + return 0; } + _inotify_fd_pid = getpid(); return 1; } @@ -78,36 +83,38 @@ int ecore_file_monitor_inotify_shutdown(void) { int fd; - Ecore_List2 *l; - for (l = _monitors; l;) - { - Ecore_File_Monitor *em; - - em = ECORE_FILE_MONITOR(l); - l = l->next; - ecore_file_monitor_inotify_del(em); - } + 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); + 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) + 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; @@ -119,17 +126,17 @@ ecore_file_monitor_inotify_add(const char *path, if (em->path[len - 1] == '/' && strcmp(em->path, "/")) em->path[len - 1] = 0; - _monitors = _ecore_list2_append(_monitors, em); + _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; + if (!_ecore_file_monitor_inotify_monitor(em, em->path)) + return NULL; } else { - ecore_file_monitor_inotify_del(em); - return NULL; + ecore_file_monitor_inotify_del(em); + return NULL; } return em; @@ -140,7 +147,8 @@ ecore_file_monitor_inotify_del(Ecore_File_Monitor *em) { int fd; - _monitors = _ecore_list2_remove(_monitors, em); + 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) @@ -149,7 +157,7 @@ ecore_file_monitor_inotify_del(Ecore_File_Monitor *em) free(em); } -static int +static Eina_Bool _ecore_file_monitor_inotify_handler(void *data __UNUSED__, Ecore_Fd_Handler *fdh) { Ecore_File_Monitor *em; @@ -162,32 +170,28 @@ _ecore_file_monitor_inotify_handler(void *data __UNUSED__, Ecore_Fd_Handler *fdh 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; + 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; + 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); + _ecore_file_monitor_inotify_events(em, (event->len ? event->name : NULL), event->mask); } - return 1; + return ECORE_CALLBACK_RENEW; } static Ecore_File_Monitor * _ecore_file_monitor_inotify_monitor_find(int wd) { - Ecore_List2 *l; + Ecore_File_Monitor *l; - for (l = _monitors; l; l = l->next) + EINA_INLIST_FOREACH(_monitors, l) { - Ecore_File_Monitor *em; - - em = ECORE_FILE_MONITOR(l); - - if (ECORE_FILE_MONITOR_INOTIFY(em)->wd == wd) - return em; + if (ECORE_FILE_MONITOR_INOTIFY(l)->wd == wd) + return l; } return NULL; } @@ -205,86 +209,101 @@ _ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask) isdir = mask & IN_ISDIR; #if 0 - _ecore_file_monitor_inotify_print(file, mask); + _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 (!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 (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 (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 (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 (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); + 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); + /* 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); + /* 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); + /* 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; - mask = IN_MODIFY| - IN_MOVED_FROM|IN_MOVED_TO| - IN_DELETE|IN_CREATE| - 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); + 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) { - printf("inotify_add_watch error\n"); - ecore_file_monitor_inotify_del(em); - return 0; + INF("inotify_add_watch failed, file was deleted"); + ecore_file_monitor_inotify_del(em); + return 0; } return 1; } @@ -320,38 +339,32 @@ _ecore_file_monitor_inotify_print(char *file, int mask) else type = "file"; + if (mask & IN_ACCESS) + INF("Inotify accessed %s: %s", type, file); if (mask & IN_MODIFY) - { - printf("Inotify modified %s: %s\n", type, file); - } + 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) - { - printf("Inotify moved from %s: %s\n", type, file); - } + INF("Inotify moved from %s: %s", type, file); if (mask & IN_MOVED_TO) - { - printf("Inotify moved to %s: %s\n", type, file); - } + INF("Inotify moved to %s: %s", type, file); if (mask & IN_DELETE) - { - printf("Inotify delete %s: %s\n", type, file); - } + INF("Inotify delete %s: %s", type, file); if (mask & IN_CREATE) - { - printf("Inotify create %s: %s\n", type, file); - } + INF("Inotify create %s: %s", type, file); if (mask & IN_DELETE_SELF) - { - printf("Inotify delete self %s: %s\n", type, file); - } + INF("Inotify delete self %s: %s", type, file); if (mask & IN_MOVE_SELF) - { - printf("Inotify move self %s: %s\n", type, file); - } + INF("Inotify move self %s: %s", type, file); if (mask & IN_UNMOUNT) - { - printf("Inotify unmount %s: %s\n", type, file); - } + 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 index abbdd22..49bfcb6 100644 --- a/src/lib/ecore_file/ecore_file_monitor_poll.c +++ b/src/lib/ecore_file/ecore_file_monitor_poll.c @@ -1,11 +1,11 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif +#include +#include +#include + #include "ecore_file_private.h" #ifdef HAVE_POLL @@ -19,7 +19,6 @@ */ typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll; -typedef struct _Ecore_File Ecore_File; #define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x)) @@ -30,24 +29,16 @@ struct _Ecore_File_Monitor_Poll unsigned char deleted; }; -struct _Ecore_File -{ - Ecore_List2 __list_data; - char *name; - int mtime; - unsigned char is_dir; -}; - #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_List2 *_monitors = NULL; +static Ecore_File_Monitor *_monitors = NULL; static int _lock = 0; -static int _ecore_file_monitor_poll_handler(void *data); +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); @@ -60,41 +51,33 @@ ecore_file_monitor_poll_init(void) int ecore_file_monitor_poll_shutdown(void) { - Ecore_List2 *l; - - for (l = _monitors; l;) - { - Ecore_File_Monitor *em; - - em = ECORE_FILE_MONITOR(l); - l = l->next; - ecore_file_monitor_poll_del(em); - } + while(_monitors) + ecore_file_monitor_poll_del(_monitors); if (_timer) { - ecore_timer_del(_timer); - _timer = NULL; + 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) + void (*func) (void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, + const char *path), + void *data) { Ecore_File_Monitor *em; - int len; + 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 @@ -109,105 +92,99 @@ ecore_file_monitor_poll_add(const char *path, 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 */ - Ecore_List *files; - char *file; - - files = ecore_file_ls(em->path); - if (files) - { - while ((file = ecore_list_next(files))) - { - Ecore_File *f; - char buf[PATH_MAX]; - - f = calloc(1, sizeof(Ecore_File)); - if (!f) - continue; - - snprintf(buf, sizeof(buf), "%s/%s", em->path, file); - f->name = strdup(file); - f->mtime = ecore_file_mod_time(buf); - f->is_dir = ecore_file_is_dir(buf); - em->files = _ecore_list2_append(em->files, f); - } - ecore_list_destroy(files); - } - } + 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; + ecore_file_monitor_poll_del(em); + return NULL; } - _monitors = _ecore_list2_append(_monitors, em); - return em; } void ecore_file_monitor_poll_del(Ecore_File_Monitor *em) { - Ecore_List2 *l; + Ecore_File *l; if (_lock) { - ECORE_FILE_MONITOR_POLL(em)->deleted = 1; - return; + 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; - - file = (Ecore_File *)l; - l = l->next; - free(file->name); - free(file); - } + for (l = em->files; l;) + { + Ecore_File *file = l; + + l = (Ecore_File *) EINA_INLIST_GET(l)->next; + free(file->name); + free(file); + } } - - _monitors = _ecore_list2_remove(_monitors, em); - + + 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); + if (!_monitors) + { + ecore_timer_del(_timer); + _timer = NULL; + } + else + ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN); } } -static int +static Eina_Bool _ecore_file_monitor_poll_handler(void *data __UNUSED__) { - Ecore_List2 *l; + Ecore_File_Monitor *l; _interval += ECORE_FILE_INTERVAL_STEP; _lock = 1; - for (l = _monitors; l; l = l->next) - { - Ecore_File_Monitor *em; - - em = ECORE_FILE_MONITOR(l); - _ecore_file_monitor_poll_check(em); - } + EINA_INLIST_FOREACH(_monitors, l) + _ecore_file_monitor_poll_check(l); _lock = 0; if (_interval > ECORE_FILE_INTERVAL_MAX) @@ -216,133 +193,134 @@ _ecore_file_monitor_poll_handler(void *data __UNUSED__) for (l = _monitors; l;) { - Ecore_File_Monitor *em; + Ecore_File_Monitor *em = l; - em = ECORE_FILE_MONITOR(l); - l = l->next; - if (ECORE_FILE_MONITOR_POLL(em)->deleted) - ecore_file_monitor_del(em); + l = ECORE_FILE_MONITOR(EINA_INLIST_GET(l)->next); + if (ECORE_FILE_MONITOR_POLL(em)->deleted) + ecore_file_monitor_del(em); } - return 1; + return ECORE_CALLBACK_RENEW; } static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em) { int mtime; - int is_dir; mtime = ecore_file_mod_time(em->path); - is_dir = ecore_file_is_dir(em->path); if (mtime < ECORE_FILE_MONITOR_POLL(em)->mtime) { - Ecore_List2 *l; - Ecore_File_Event event; - - /* Notify all files deleted */ - for (l = em->files; l;) - { - Ecore_File *f; - char buf[PATH_MAX]; - - f = (Ecore_File *)l; - l = 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; + 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_List2 *l; - - /* Check for changed files */ - for (l = em->files; l;) - { - Ecore_File *f; - char buf[PATH_MAX]; - int mtime; - Ecore_File_Event event; - - f = (Ecore_File *)l; - l = l->next; - - snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name); - mtime = ecore_file_mod_time(buf); - if (mtime < 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_list2_remove(em->files, f); - free(f->name); - free(f); - _interval = ECORE_FILE_INTERVAL_MIN; - } - else if ((mtime > f->mtime) && !(f->is_dir)) - { - em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf); - _interval = ECORE_FILE_INTERVAL_MIN; - f->mtime = mtime; - } - else - f->mtime = mtime; - } - - /* Check for new files */ - if (ECORE_FILE_MONITOR_POLL(em)->mtime < mtime) - { - Ecore_List *files; - 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*/ - while ((file = ecore_list_next(files))) - { - 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_list2_append(em->files, f); - } - ecore_list_destroy(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 *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; } @@ -350,15 +328,12 @@ _ecore_file_monitor_poll_check(Ecore_File_Monitor *em) static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name) { - Ecore_List2 *l; + Ecore_File *l; - for (l = em->files; l; l = l->next) + EINA_INLIST_FOREACH(em->files, l) { - Ecore_File *f; - - f = (Ecore_File *)l; - if (!strcmp(f->name, name)) - return 1; + if (!strcmp(l->name, name)) + return 1; } return 0; } 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 index 7100d95..3c06e9b 100644 --- a/src/lib/ecore_file/ecore_file_path.c +++ b/src/lib/ecore_file/ecore_file_path.c @@ -1,49 +1,63 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #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 int init = 0; -static Ecore_List *__ecore_file_path_bin = NULL; +static Eina_List *__ecore_file_path_bin = NULL; -static Ecore_List *_ecore_file_path_from_env(const char *env); +static Eina_List *_ecore_file_path_from_env(const char *env); -int +void ecore_file_path_init(void) { - if (++init != 1) return init; __ecore_file_path_bin = _ecore_file_path_from_env("PATH"); - ecore_list_free_cb_set(__ecore_file_path_bin, free); - return init; } -int +void ecore_file_path_shutdown(void) { - if (--init != 0) return init; - ecore_list_destroy(__ecore_file_path_bin); - __ecore_file_path_bin = NULL; - return init; + char *dir; + + EINA_LIST_FREE(__ecore_file_path_bin, dir) + eina_stringshare_del(dir); } -Ecore_List * +Eina_List * _ecore_file_path_from_env(const char *env) { - Ecore_List *path; - char *env_path, *p, *last; - - path = ecore_list_new(); + Eina_List *path = NULL; + char *env_tmp, *env_path, *p, *last; - env_path = getenv(env); - if (!env_path) + env_tmp = getenv(env); + if (!env_tmp) return path; - env_path = strdup(env_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++) { @@ -52,91 +66,119 @@ _ecore_file_path_from_env(const char *env) if (!*p) { - if (!ecore_file_path_dir_exists(last)) - ecore_list_append(path, strdup(last)); + if (!ecore_file_path_dir_exists(last)) + path = eina_list_append(path, eina_stringshare_add(last)); last = p + 1; } } if (p > last) - ecore_list_append(path, strdup(last)); + path = eina_list_append(path, eina_stringshare_add(last)); - free(env_path); return path; } /** - * Check if the given directory is in PATH - * @param The name of the directory to search in PATH - * @return 1 if the directory exist in PATH, 0 otherwise + * @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 int +EAPI Eina_Bool ecore_file_path_dir_exists(const char *in_dir) { + Eina_List *l; char *dir; - if (!__ecore_file_path_bin) return 0; - ecore_list_first_goto(__ecore_file_path_bin); - while ((dir = ecore_list_next(__ecore_file_path_bin)) != NULL) + 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 1; + if (strcmp(dir, in_dir)) + return EINA_TRUE; } - return 0; + + return EINA_FALSE; } /** - * Check if the given application is installed + * @brief Check if the given application is installed. + * * @param exe The name of the application - * @return 1 if the exe is in PATH and is executable - * - * This function check if the given name exist in PATH and is executable + * @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 int +EAPI Eina_Bool ecore_file_app_installed(const char *exe) { + Eina_List *l; char *dir; char buf[PATH_MAX]; - if (!exe) return 0; - if (ecore_file_can_exec(exe)) return 1; + if (!exe) return EINA_FALSE; + if (ecore_file_can_exec(exe)) return EINA_TRUE; - ecore_list_first_goto(__ecore_file_path_bin); - while ((dir = ecore_list_next(__ecore_file_path_bin)) != NULL) + EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir) { - snprintf(buf, sizeof(buf), "%s/%s", dir, exe); - if (ecore_file_can_exec(buf)) return 1; + snprintf(buf, sizeof(buf), "%s/%s", dir, exe); + if (ecore_file_can_exec(buf)) + return EINA_TRUE; } - return 0; + + return EINA_FALSE; } /** - * Get a list of all the applications installed on the system - * @return An Ecore_List containing all the executable files in the system + * @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 Ecore_List * +EAPI Eina_List * ecore_file_app_list(void) { - Ecore_List *list, *files; + Eina_List *list = NULL; + Eina_List *files; + Eina_List *l; char buf[PATH_MAX], *dir, *exe; - - list = ecore_list_new(); - if (!list) return NULL; - ecore_list_free_cb_set(list, free); - ecore_list_first_goto(__ecore_file_path_bin); - while ((dir = ecore_list_next(__ecore_file_path_bin)) != NULL) + + EINA_LIST_FOREACH(__ecore_file_path_bin, l, dir) { - files = ecore_file_ls(dir); - if (files) - { - ecore_list_first_goto(files); - while ((exe = ecore_list_next(files)) != NULL) - { - snprintf(buf, sizeof(buf), "%s/%s", dir, exe); - if ((ecore_file_can_exec(buf)) && - (!ecore_file_is_dir(buf))) - ecore_list_append(list, strdup(buf)); - } - ecore_list_destroy(files); - } + 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 index e2001f7..45d2cbd 100644 --- a/src/lib/ecore_file/ecore_file_private.h +++ b/src/lib/ecore_file/ecore_file_private.h @@ -1,68 +1,129 @@ -#ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -#endif +#ifndef ECORE_FILE_PRIVATE_H_ +#define ECORE_FILE_PRIVATE_H_ #ifdef __linux__ # include #endif -#include "Ecore.h" -#include "ecore_private.h" - #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); -int ecore_file_monitor_shutdown(void); +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 { - Ecore_List2 __list_data; + EINA_INLIST; void (*func) (void *data, - Ecore_File_Monitor *ecore_file_monitor, - Ecore_File_Event event, - const char *path); + Ecore_File_Monitor *ecore_file_monitor, + Ecore_File_Event event, + const char *path); char *path; void *data; - Ecore_List2 *files; + 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 (*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 (*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 */ -int ecore_file_path_init(void); -int ecore_file_path_shutdown(void); +void ecore_file_path_init(void); +void ecore_file_path_shutdown(void); /* ecore_file_download */ -int ecore_file_download_init(void); -int ecore_file_download_shutdown(void); +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 index d839819..641ece7 100644 --- a/src/lib/ecore_imf/Ecore_IMF.h +++ b/src/lib/ecore_imf/Ecore_IMF.h @@ -1,10 +1,8 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef _ECORE_IMF_H #define _ECORE_IMF_H +#include + #ifdef EAPI # undef EAPI #endif @@ -31,312 +29,546 @@ # endif #endif /* ! _WIN32 */ -#include - #ifdef __cplusplus extern "C" { #endif - /* 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 */ - - 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 enum - { - ECORE_IMF_EVENT_MOUSE_DOWN, - ECORE_IMF_EVENT_MOUSE_UP, - ECORE_IMF_EVENT_MOUSE_IN, - ECORE_IMF_EVENT_MOUSE_OUT, - ECORE_IMF_EVENT_MOUSE_MOVE, - ECORE_IMF_EVENT_MOUSE_WHEEL, - ECORE_IMF_EVENT_KEY_DOWN, - ECORE_IMF_EVENT_KEY_UP - } Ecore_IMF_Event_Type; - - 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_Modifiers; - - 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 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; - - 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 occured */ - }; - - 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 occured */ - }; - - 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 occured */ - }; - - 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 occured */ - }; - - 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 occured */ - }; - - 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 occured */ - }; - - struct _Ecore_IMF_Event_Key_Down - { - 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 occured */ - }; - - struct _Ecore_IMF_Event_Key_Up - { - 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 occured */ - }; - - 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_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, int use_preedit); - void (*input_mode_set) (Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode input_mode); - int (*filter_event) (Ecore_IMF_Context *ctx, Ecore_IMF_Event_Type type, Ecore_IMF_Event *event); - }; - - 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 Ecore_List *ecore_imf_context_available_ids_get(void); - EAPI Ecore_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_canvas_set(Ecore_IMF_Context *ctx, void *canvas); - 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_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_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit); - EAPI void ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int (*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 int 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 int 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); - - /* 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); - */ +/** + * @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_SUB4, /**< Substring style 4 @since 1.8 */ + ECORE_IMF_PREEDIT_TYPE_SUB5, /**< Substring style 5 @since 1.8 */ + ECORE_IMF_PREEDIT_TYPE_SUB6, /**< Substring style 6 @since 1.8 */ + ECORE_IMF_PREEDIT_TYPE_SUB7 /**< Substring style 7 @since 1.8 */ +} 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 including esc, alt, ctrl key, so on (no auto-correct, no auto-capitalization) @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_SIGNIN /**< Sign-in @since 1.8 */ +} 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 } diff --git a/src/lib/ecore_imf/Makefile.am b/src/lib/ecore_imf/Makefile.am index f13a264..10f6c2f 100644 --- a/src/lib/ecore_imf/Makefile.am +++ b/src/lib/ecore_imf/Makefile.am @@ -1,31 +1,28 @@ MAINTAINERCLEANFILES = Makefile.in -if BUILD_ECORE_IMF AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ --DPACKAGE_LIB_DIR=\"$(libdir)\" +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +@EFL_ECORE_IMF_BUILD@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ AM_CFLAGS = @WIN32_CFLAGS@ lib_LTLIBRARIES = libecore_imf.la -include_HEADERS = \ -Ecore_IMF.h +includes_HEADERS = Ecore_IMF.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_imf_la_SOURCES = \ ecore_imf.c \ ecore_imf_context.c \ -ecore_imf_module.c \ -ecore_imf_private.h +ecore_imf_module.c libecore_imf_la_LIBADD = \ -$(top_builddir)/src/lib/ecore/libecore.la +$(top_builddir)/src/lib/ecore/libecore.la \ +@EINA_LIBS@ \ +@EVIL_LIBS@ -libecore_imf_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ -endif +libecore_imf_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ -EXTRA_DIST = \ -Ecore_IMF.h \ -ecore_imf.c \ -ecore_imf_context.c \ -ecore_imf_module.c \ -ecore_imf_private.h +EXTRA_DIST = ecore_imf_private.h diff --git a/src/lib/ecore_imf/ecore_imf.c b/src/lib/ecore_imf/ecore_imf.c index caf9671..7cf8a4a 100644 --- a/src/lib/ecore_imf/ecore_imf.c +++ b/src/lib/ecore_imf/ecore_imf.c @@ -1,21 +1,21 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif -#include "config.h" +#include +#include #include "Ecore_IMF.h" #include "ecore_imf_private.h" -#include - 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; -static int init_count = 0; +int _ecore_imf_log_dom = -1; +static int _ecore_imf_init_count = 0; /** * @defgroup Ecore_IMF_Lib_Group Ecore Input Method Library Functions @@ -33,9 +33,17 @@ static int init_count = 0; EAPI int ecore_imf_init(void) { - if (++init_count != 1) return init_count; + if (++_ecore_imf_init_count != 1) return _ecore_imf_init_count; - ecore_init(); + 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(); @@ -44,7 +52,7 @@ ecore_imf_init(void) ECORE_IMF_EVENT_COMMIT = ecore_event_type_new(); ECORE_IMF_EVENT_DELETE_SURROUNDING = ecore_event_type_new(); - return init_count; + return _ecore_imf_init_count; } /** @@ -56,10 +64,10 @@ ecore_imf_init(void) EAPI int ecore_imf_shutdown(void) { - if (--init_count != 0) return init_count; - - ecore_shutdown(); + if (--_ecore_imf_init_count != 0) return _ecore_imf_init_count; ecore_imf_module_shutdown(); - - return init_count; + 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 index 83f1fd4..d9aeca9 100644 --- a/src/lib/ecore_imf/ecore_imf_context.c +++ b/src/lib/ecore_imf/ecore_imf_context.c @@ -1,40 +1,57 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif -#include #include +#include +#include -#include "config.h" +#include +#include #include "Ecore_IMF.h" #include "ecore_imf_private.h" -#include - /** * @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 Ecore_List + * 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 Ecore_List of strings; + * @return Return an Eina_List of strings; * on failure it returns NULL. * @ingroup Ecore_IMF_Context_Group */ -EAPI Ecore_List * +EAPI Eina_List * ecore_imf_context_available_ids_get(void) { return ecore_imf_module_context_ids_get(); } -EAPI Ecore_List * +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); @@ -51,16 +68,16 @@ ecore_imf_context_available_ids_by_canvas_type_get(const char *canvas_type) static int _ecore_imf_context_match_locale(const char *locale, const char *against, int against_len) { - if (strcmp(against, "*") == 0) - return 1; + if (strcmp(against, "*") == 0) + return 1; - if (strcasecmp(locale, against) == 0) - return 4; + if (strcasecmp(locale, against) == 0) + return 4; - if (strncasecmp(locale, against, 2) == 0) - return (against_len == 2) ? 3 : 2; + if (strncasecmp(locale, against, 2) == 0) + return (against_len == 2) ? 3 : 2; - return 0; + return 0; } /** @@ -82,7 +99,7 @@ EAPI const char * ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type) { const char *id; - Ecore_List *modules; + Eina_List *modules; Ecore_IMF_Module *module; char *locale; char *tmp; @@ -91,8 +108,8 @@ ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type) id = getenv("ECORE_IMF_MODULE"); if (id) { - if (strcmp(id, "none") == 0) return NULL; - if (ecore_imf_module_get(id)) return id; + if (strcmp(id, "none") == 0) return NULL; + if (ecore_imf_module_get(id)) return id; } modules = ecore_imf_module_available_get(); @@ -110,29 +127,27 @@ ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type) id = NULL; - ecore_list_first_goto(modules); - while ((module = ecore_list_next(modules))) + 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 ? q - p : strlen (p)); - - if (goodness > best_goodness) - { - id = module->info->id; - best_goodness = goodness; - } - - p = q ? q + 1 : NULL; - } + 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; + } } - ecore_list_destroy(modules); free(locale); return id; @@ -145,6 +160,32 @@ ecore_imf_context_default_id_by_canvas_type_get(const char *canvas_type) * @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) @@ -174,9 +215,26 @@ ecore_imf_context_add(const char *id) 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 1, so let's make sure it's + /* 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_use_preedit_set(ctx, 1); + 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); @@ -196,9 +254,9 @@ 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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_info_get"); + return NULL; } return ctx->module->info; } @@ -212,13 +270,22 @@ ecore_imf_context_info_get(Ecore_IMF_Context *ctx) 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; + 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); } @@ -230,7 +297,7 @@ ecore_imf_context_del(Ecore_IMF_Context *ctx) * 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 NULL to indicate + * @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 */ @@ -239,11 +306,34 @@ 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; + 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; } /** @@ -255,8 +345,8 @@ ecore_imf_context_client_window_set(Ecore_IMF_Context *ctx, void *window) * also be used for purposes internal to the Input Method Context. * * @param ctx An #Ecore_IMF_Context. - * @param canas The client canvas. This may be NULL to indicate - * that the previous client canvas no longer exists. + * @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 @@ -264,11 +354,34 @@ 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_window_set"); - return; + 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; } /** @@ -282,9 +395,9 @@ 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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_show"); + return; } if (ctx->klass->show) ctx->klass->show(ctx); } @@ -300,14 +413,14 @@ 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; + 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. * @@ -323,16 +436,88 @@ ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cu { if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_preedit_string_get"); - return; + 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; + 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; } } @@ -342,15 +527,27 @@ ecore_imf_context_preedit_string_get(Ecore_IMF_Context *ctx, char **str, int *cu * * @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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_focus_in"); + return; } if (ctx->klass->focus_in) ctx->klass->focus_in(ctx); } @@ -361,15 +558,27 @@ ecore_imf_context_focus_in(Ecore_IMF_Context *ctx) * * @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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_focus_out"); + return; } if (ctx->klass->focus_out) ctx->klass->focus_out(ctx); } @@ -381,15 +590,27 @@ ecore_imf_context_focus_out(Ecore_IMF_Context *ctx) * * @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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_reset"); + return; } if (ctx->klass->reset) ctx->klass->reset(ctx); } @@ -407,17 +628,43 @@ 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; + 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 @use_preedit is 0 (default - * is 1), then the IM context may use some other method to display + * 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. @@ -425,19 +672,113 @@ ecore_imf_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos) * @ingroup Ecore_IMF_Context_Group */ EAPI void -ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit) +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; + 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 the callback to be used on get_surrounding request. + * 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. + * @note Default value is EINA_TRUE. + * @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. + * @note Default type is ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE. + * @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. @@ -448,13 +789,13 @@ ecore_imf_context_use_preedit_set(Ecore_IMF_Context *ctx, int use_preedit) * @ingroup Ecore_IMF_Context_Group */ EAPI void -ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int (*func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos), const void *data) +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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_retrieve_surrounding_callback_set"); + return; } ctx->retrieve_surrounding_func = func; @@ -465,7 +806,7 @@ ecore_imf_context_retrieve_surrounding_callback_set(Ecore_IMF_Context *ctx, int * 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. The default input mode is * ECORE_IMF_INPUT_MODE_FULL. * * @param ctx An #Ecore_IMF_Context. @@ -477,9 +818,9 @@ ecore_imf_context_input_mode_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Mode in { if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_input_mode_set"); - return; + 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; @@ -499,39 +840,61 @@ 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; + 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 1, then no further processing + * 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 0 if the event was not handled), but there is no + * 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 1 if the event was handled; otherwise 0. + * @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 int +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 0; + 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 0; + return EINA_FALSE; } /** @@ -556,7 +919,7 @@ ecore_imf_context_new(const Ecore_IMF_Context_Class *ctxc) Ecore_IMF_Context *ctx; if (!ctxc) return NULL; - ctx = malloc(sizeof(Ecore_IMF_Context)); + ctx = calloc(1, sizeof(Ecore_IMF_Context)); if (!ctx) return NULL; ECORE_MAGIC_SET(ctx, ECORE_MAGIC_CONTEXT); ctx->klass = ctxc; @@ -583,9 +946,9 @@ 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; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_data_set"); + return; } ctx->data = data; } @@ -603,54 +966,58 @@ 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; + 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 + * 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 1, then you must free + * 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 @text. - * @return 1 if surrounding text was provided; otherwise 0. + * 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 int +EAPI Eina_Bool ecore_imf_context_surrounding_get(Ecore_IMF_Context *ctx, char **text, int *cursor_pos) { - int result = 0; + 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 0; + 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; - } + 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; } @@ -664,6 +1031,10 @@ _ecore_imf_event_free_preedit(void *data __UNUSED__, void *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 */ @@ -674,20 +1045,24 @@ ecore_imf_context_preedit_start_event_add(Ecore_IMF_Context *ctx) if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_preedit_start_event_add"); - return; + 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); + 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 */ @@ -698,20 +1073,23 @@ ecore_imf_context_preedit_end_event_add(Ecore_IMF_Context *ctx) if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_preedit_end_event_add"); - return; + 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); + 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 */ @@ -722,15 +1100,15 @@ ecore_imf_context_preedit_changed_event_add(Ecore_IMF_Context *ctx) if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_preedit_changed_event_add"); - return; + 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); + ev, _ecore_imf_event_free_preedit, NULL); } static void @@ -746,6 +1124,9 @@ _ecore_imf_event_free_commit(void *data __UNUSED__, void *event) /** * 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 @@ -757,16 +1138,16 @@ ecore_imf_context_commit_event_add(Ecore_IMF_Context *ctx, const char *str) if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_commit_event_add"); - return; + 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); + ev, _ecore_imf_event_free_commit, NULL); } @@ -779,6 +1160,13 @@ _ecore_imf_event_free_delete_surrounding(void *data __UNUSED__, void *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. @@ -791,9 +1179,9 @@ ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offse if (!ECORE_MAGIC_CHECK(ctx, ECORE_MAGIC_CONTEXT)) { - ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, - "ecore_imf_context_delete_surrounding_event_add"); - return; + ECORE_MAGIC_FAIL(ctx, ECORE_MAGIC_CONTEXT, + "ecore_imf_context_delete_surrounding_event_add"); + return; } ev = malloc(sizeof(Ecore_IMF_Event_Delete_Surrounding)); @@ -801,5 +1189,712 @@ ecore_imf_context_delete_surrounding_event_add(Ecore_IMF_Context *ctx, int offse ev->offset = offset; ev->n_chars = n_chars; ecore_event_add(ECORE_IMF_EVENT_DELETE_SURROUNDING, - ev, _ecore_imf_event_free_delete_surrounding, NULL); + 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 + * @note Default layout type is ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL. + * @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 + * @note Default type is ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT. + * @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 index d6b0be1..946f5bc 100644 --- a/src/lib/ecore_imf/ecore_imf_module.c +++ b/src/lib/ecore_imf/ecore_imf_module.c @@ -1,44 +1,43 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif -#include #include #include +#include +#include -#include "config.h" +#include +#include +#include "Ecore_IMF.h" #include "ecore_imf_private.h" -static void _ecore_imf_module_load_all(void); -static void _ecore_imf_module_append(Ecore_Plugin *plugin, const Ecore_IMF_Context_Info *info, Ecore_IMF_Context *(*imf_module_create)(void)); static void _ecore_imf_module_free(Ecore_IMF_Module *module); static int _ecore_imf_modules_exists(const char *ctx_id); -static Ecore_Path_Group *ecore_imf_modules_path = NULL; -static Ecore_Hash *modules = NULL; +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 pathname[PATH_MAX]; - const char *homedir; - - ecore_imf_modules_path = ecore_path_group_new(); - snprintf(pathname, sizeof(pathname), "%s/ecore/immodules/", - PACKAGE_LIB_DIR); - ecore_path_group_add(ecore_imf_modules_path, pathname); + char *homedir; - homedir = getenv("HOME"); + 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) { - snprintf(pathname, sizeof(pathname), "%s/.ecore/immodules/", - homedir); - ecore_path_group_add(ecore_imf_modules_path, pathname); + module_list = eina_module_list_get(module_list, homedir, 0, NULL, NULL); + free(homedir); } - - modules = NULL; - _ecore_imf_module_load_all(); + eina_module_list_load(module_list); } void @@ -46,36 +45,38 @@ ecore_imf_module_shutdown(void) { if (modules) { - ecore_hash_destroy(modules); - modules = NULL; + eina_hash_free(modules); + modules = NULL; } + if (module_list) + { + eina_module_list_free(module_list); + eina_array_free(module_list); + module_list = NULL; + } +} - ecore_path_group_del(ecore_imf_modules_path); - ecore_imf_modules_path = 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; } -Ecore_List * +Eina_List * ecore_imf_module_available_get(void) { - Ecore_List *values; - unsigned int i = 0; + Eina_List *values = NULL; + Eina_Iterator *it = NULL; if (!modules) return NULL; - /* ecore_hash_values() */ - values = ecore_list_new(); - while (i < ecore_prime_table[modules->size]) - { - if (modules->buckets[i]) - { - Ecore_Hash_Node *node; - - for (node = modules->buckets[i]; node; node = node->next) - ecore_list_append(values, node->value); - } - i++; - } - ecore_list_first_goto(values); + 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; } @@ -84,7 +85,7 @@ Ecore_IMF_Module * ecore_imf_module_get(const char *ctx_id) { if (!modules) return NULL; - return ecore_hash_get(modules, ctx_id); + return eina_hash_find(modules, ctx_id); } Ecore_IMF_Context * @@ -94,150 +95,107 @@ ecore_imf_module_context_create(const char *ctx_id) Ecore_IMF_Context *ctx = NULL; if (!modules) return NULL; - module = ecore_hash_get(modules, ctx_id); + 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; + 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; } -Ecore_List * +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; - return ecore_hash_keys(modules); + + 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; } -Ecore_List * +Eina_List * ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type) { - Ecore_List *values; - unsigned int i = 0; + 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(); - values = ecore_list_new(); - while (i < ecore_prime_table[modules->size]) - { - if (modules->buckets[i]) - { - Ecore_Hash_Node *node; - - for (node = modules->buckets[i]; node; node = node->next) - { - Ecore_IMF_Module *module = node->value; - if (strcmp(module->info->canvas_type, canvas_type) == 0) - ecore_list_append(values, (void *) module->info->id); - } - } - i++; - } - ecore_list_first_goto(values); + it = eina_hash_iterator_data_new(modules); + if (!it) + return NULL; - return values; -} + 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); -static void -_ecore_imf_module_load_all(void) -{ - Ecore_List *avail; - char *filename; - Ecore_Plugin *plugin; - const Ecore_IMF_Context_Info *info = NULL; - int (*imf_module_init)(const Ecore_IMF_Context_Info **info); - Ecore_IMF_Context *(*imf_module_create)(void); - - avail = ecore_plugin_available_get(ecore_imf_modules_path); - if (!avail) return; - - ecore_list_first_goto(avail); - while ((filename = ecore_list_next(avail))) - { - plugin = ecore_plugin_load(ecore_imf_modules_path, filename, NULL); - if (!plugin) - { - fprintf(stderr, "** ecore_imf: Error loading input method plugin %s!\n", - filename); - continue; - } - - imf_module_init = ecore_plugin_symbol_get(plugin, "imf_module_init"); - if (!imf_module_init || !imf_module_init(&info) || !info) - { - fprintf(stderr, "** ecore_imf: Error initializing input method plugin %s! " - "'imf_module_init' is missing or failed to run!", - filename); - ecore_plugin_unload(plugin); - continue; - } - - if (_ecore_imf_modules_exists(info->id)) - { - fprintf(stderr, "** ecore_imf: Error loading input method plugin %s! " - "Plugin with id='%s' already exists!", - filename, info->id); - ecore_plugin_unload(plugin); - continue; - } - - imf_module_create = ecore_plugin_symbol_get(plugin, "imf_module_create"); - if (!imf_module_create) - { - fprintf(stderr, "** ecore_imf: Error setting up input method plugin %s! " - "'imf_module_create' is missing!", - filename); - ecore_plugin_unload(plugin); - continue; - } - - _ecore_imf_module_append(plugin, info, imf_module_create); - } - - ecore_list_destroy(avail); + return values; } -static void -_ecore_imf_module_append(Ecore_Plugin *plugin, - const Ecore_IMF_Context_Info *info, - Ecore_IMF_Context *(*imf_module_create)(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)) { Ecore_IMF_Module *module; + if (_ecore_imf_modules_exists(info->id)) return; + if (!modules) - { - modules = ecore_hash_new(ecore_str_hash, ecore_str_compare); - ecore_hash_free_key_cb_set(modules, free); - ecore_hash_free_value_cb_set(modules, (Ecore_Free_Cb) _ecore_imf_module_free); - } + modules = eina_hash_string_superfast_new(EINA_FREE_CB(_ecore_imf_module_free)); module = malloc(sizeof(Ecore_IMF_Module)); - module->plugin = plugin; module->info = info; /* cache imf_module_create as it may be used several times */ module->create = imf_module_create; + module->exit = imf_module_exit; - ecore_hash_set(modules, strdup(info->id), module); + eina_hash_add(modules, info->id, module); } static void _ecore_imf_module_free(Ecore_IMF_Module *module) { - int (*imf_module_exit)(void); - - imf_module_exit = ecore_plugin_symbol_get(module->plugin, "imf_module_exit"); - if (imf_module_exit) imf_module_exit(); - ecore_plugin_unload(module->plugin); + if (module->exit) module->exit(); free(module); } @@ -245,5 +203,10 @@ static int _ecore_imf_modules_exists(const char *ctx_id) { if (!modules) return 0; - return (ecore_hash_get(modules, ctx_id) != NULL); + 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 index dd951e2..b4ff0f2 100644 --- a/src/lib/ecore_imf/ecore_imf_private.h +++ b/src/lib/ecore_imf/ecore_imf_private.h @@ -1,13 +1,41 @@ #ifndef _ECORE_IMF_PRIVATE_H #define _ECORE_IMF_PRIVATE_H -#include "Ecore_IMF.h" +#define ECORE_MAGIC_CONTEXT 0x56c1b39a -#include "ecore_private.h" +#ifdef ECORE_IMF_DEFAULT_LOG_COLOR +#undef ECORE_IMF_DEFAULT_LOG_COLOR +#endif +#define ECORE_IMF_DEFAULT_LOG_COLOR EINA_COLOR_BLUE -#define ECORE_MAGIC_CONTEXT 0x56c1b39a +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 { @@ -16,23 +44,41 @@ struct _Ecore_IMF_Context const Ecore_IMF_Context_Class *klass; void *data; int input_mode; - int (*retrieve_surrounding_func)(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos); + 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 { - Ecore_Plugin *plugin; 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); -Ecore_List *ecore_imf_module_available_get(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); -Ecore_List *ecore_imf_module_context_ids_get(void); -Ecore_List *ecore_imf_module_context_ids_by_canvas_type_get(const char *canvas_type); +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 index ea99324..5f7cdb9 100644 --- a/src/lib/ecore_imf_evas/Ecore_IMF_Evas.h +++ b/src/lib/ecore_imf_evas/Ecore_IMF_Evas.h @@ -1,6 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ #ifndef _ECORE_IMF_EVAS_H #define _ECORE_IMF_EVAS_H @@ -12,7 +9,7 @@ #endif #ifdef _WIN32 -# ifdef EFL_ECORE_IMF_BUILD +# ifdef EFL_ECORE_IMF_EVAS_BUILD # ifdef DLL_EXPORT # define EAPI __declspec(dllexport) # else @@ -20,7 +17,7 @@ # endif /* ! DLL_EXPORT */ # else # define EAPI __declspec(dllimport) -# endif /* ! EFL_ECORE_EVAS_BUILD */ +# endif /* ! EFL_ECORE_IMF_BUILD */ #else # ifdef __GNUC__ # if __GNUC__ >= 4 @@ -37,14 +34,14 @@ 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); +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 } diff --git a/src/lib/ecore_imf_evas/Makefile.am b/src/lib/ecore_imf_evas/Makefile.am index d41fc2d..fa5c491 100644 --- a/src/lib/ecore_imf_evas/Makefile.am +++ b/src/lib/ecore_imf_evas/Makefile.am @@ -1,28 +1,22 @@ MAINTAINERCLEANFILES = Makefile.in -if BUILD_ECORE_IMF_EVAS AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_srcdir)/src/lib/ecore_imf \ -@EVAS_CFLAGS@ +@EFL_ECORE_IMF_EVAS_BUILD@ \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ lib_LTLIBRARIES = libecore_imf_evas.la -include_HEADERS = \ -Ecore_IMF_Evas.h +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@ +@EVAS_LIBS@ \ +@EINA_LIBS@ -libecore_imf_evas_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore_imf/libecore_imf.la - -libecore_imf_evas_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ -endif - -EXTRA_DIST = \ -Ecore_IMF_Evas.h \ -ecore_imf_evas.c +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 index a60a5b0..4a5f3dd 100644 --- a/src/lib/ecore_imf_evas/ecore_imf_evas.c +++ b/src/lib/ecore_imf_evas/ecore_imf_evas.c @@ -1,25 +1,28 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ #ifdef HAVE_CONFIG_H # include #endif +#include +#include "ecore_private.h" #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 char *_ecore_imf_evas_event_empty = ""; +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) + Ecore_IMF_Keyboard_Modifiers *imf_keyboard_modifiers) { if (!evas_modifiers || !imf_keyboard_modifiers) return; @@ -33,12 +36,14 @@ _ecore_imf_evas_event_modifiers_wrap(Evas_Modifier *evas_modifiers, *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) + Ecore_IMF_Keyboard_Locks *imf_keyboard_locks) { if (!evas_locks || !imf_keyboard_locks) return; @@ -55,7 +60,7 @@ _ecore_imf_evas_event_locks_wrap(Evas_Lock *evas_locks, /* 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) + Ecore_IMF_Mouse_Flags *imf_flags) { if (!imf_flags) return; @@ -76,7 +81,7 @@ _ecore_imf_evas_event_mouse_flags_wrap(Evas_Button_Flags evas_flags, */ EAPI void ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event, - Ecore_IMF_Event_Mouse_In *imf_event) + Ecore_IMF_Event_Mouse_In *imf_event) { if (!evas_event || !imf_event) return; @@ -100,7 +105,7 @@ ecore_imf_evas_event_mouse_in_wrap(Evas_Event_Mouse_In *evas_event, */ EAPI void ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event, - Ecore_IMF_Event_Mouse_Out *imf_event) + Ecore_IMF_Event_Mouse_Out *imf_event) { if (!evas_event || !imf_event) return; @@ -124,7 +129,7 @@ ecore_imf_evas_event_mouse_out_wrap(Evas_Event_Mouse_Out *evas_event, */ EAPI void ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event, - Ecore_IMF_Event_Mouse_Move *imf_event) + Ecore_IMF_Event_Mouse_Move *imf_event) { if (!evas_event || !imf_event) return; @@ -152,7 +157,7 @@ ecore_imf_evas_event_mouse_move_wrap(Evas_Event_Mouse_Move *evas_event, */ EAPI void ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event, - Ecore_IMF_Event_Mouse_Down *imf_event) + Ecore_IMF_Event_Mouse_Down *imf_event) { if (!evas_event || !imf_event) return; @@ -177,7 +182,7 @@ ecore_imf_evas_event_mouse_down_wrap(Evas_Event_Mouse_Down *evas_event, */ EAPI void ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event, - Ecore_IMF_Event_Mouse_Up *imf_event) + Ecore_IMF_Event_Mouse_Up *imf_event) { if (!evas_event || !imf_event) return; @@ -202,7 +207,7 @@ ecore_imf_evas_event_mouse_up_wrap(Evas_Event_Mouse_Up *evas_event, */ EAPI void ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event, - Ecore_IMF_Event_Mouse_Wheel *imf_event) + Ecore_IMF_Event_Mouse_Wheel *imf_event) { if (!evas_event || !imf_event) return; @@ -225,10 +230,32 @@ ecore_imf_evas_event_mouse_wheel_wrap(Evas_Event_Mouse_Wheel *evas_event, * @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) + Ecore_IMF_Event_Key_Down *imf_event) { if (!evas_event || !imf_event) return; @@ -248,11 +275,45 @@ ecore_imf_evas_event_key_down_wrap(Evas_Event_Key_Down *evas_event, * @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) + Ecore_IMF_Event_Key_Up *imf_event) { + if (!evas_event) + { + EINA_LOG_ERR("Evas event is missing"); + return; + } + + if (!imf_event) + { + EINA_LOG_ERR("Imf event is missing"); + 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; diff --git a/src/lib/ecore_input/Ecore_Input.h b/src/lib/ecore_input/Ecore_Input.h new file mode 100644 index 0000000..d1feb22 --- /dev/null +++ b/src/lib/ecore_input/Ecore_Input.h @@ -0,0 +1,236 @@ +#ifndef _ECORE_INPUT_H +#define _ECORE_INPUT_H + +#ifdef _WIN32 +# include +#else +# include +#endif + +#include + +#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 index b420cf2..f77870f 100644 --- a/src/lib/ecore_ipc/Ecore_Ipc.h +++ b/src/lib/ecore_ipc/Ecore_Ipc.h @@ -1,12 +1,19 @@ #ifndef _ECORE_IPC_H #define _ECORE_IPC_H +#include + #ifdef EAPI -#undef EAPI +# undef EAPI #endif -#ifdef _MSC_VER -# ifdef BUILDING_DLL -# define EAPI __declspec(dllexport) + +#ifdef _WIN32 +# ifdef EFL_ECORE_IPC_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif # else # define EAPI __declspec(dllimport) # endif @@ -22,8 +29,6 @@ # endif #endif -#include - /** * @file Ecore_Ipc.h * @brief Ecore inter-process communication functions. @@ -32,17 +37,12 @@ #ifdef __cplusplus extern "C" { #endif - -#ifndef _ECORE_IPC_PRIVATE_H - typedef void Ecore_Ipc_Server; /**< An IPC connection handle */ - typedef void Ecore_Ipc_Client; /**< An IPC connection handle */ -#endif -/** - * Macros used for generic data packing - */ -EAPI unsigned short _ecore_ipc_swap_16(unsigned short v); -EAPI unsigned int _ecore_ipc_swap_32(unsigned int v); +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 @@ -69,44 +69,44 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); /* unpacking */ #define ECORE_IPC_GET64(v)\ { \ - p->v = ECORE_IPC_SWAP2CPU64(*(long long *)(ptr)); \ - ptr += 8; \ + p->v = ECORE_IPC_SWAP2CPU64(*(long long *)(ptr)); \ + ptr += 8; \ } #define ECORE_IPC_GET32(v)\ { \ - p->v = ECORE_IPC_SWAP2CPU32(*(int *)(ptr)); \ - ptr += 4; \ + p->v = ECORE_IPC_SWAP2CPU32(*(int *)(ptr)); \ + ptr += 4; \ } #define ECORE_IPC_GET16(v)\ { \ - p->v = ECORE_IPC_SWAP2CPU16(*(short *)(ptr)); \ - ptr += 2; \ + p->v = ECORE_IPC_SWAP2CPU16(*(short *)(ptr)); \ + ptr += 2; \ } #define ECORE_IPC_GET8(v) \ { \ - p->v = ECORE_IPC_SWAP2CPU8(*(char *)(ptr)); \ - ptr += 1; \ + 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; \ + *(long long *)(ptr) = ECORE_IPC_SWAP2NET64(p->v); \ + ptr += 8; \ } #define ECORE_IPC_PUT32(v)\ { \ - *(int *)(ptr) = ECORE_IPC_SWAP2NET32(p->v); \ - ptr += 4; \ + *(int *)(ptr) = ECORE_IPC_SWAP2NET32(p->v); \ + ptr += 4; \ } #define ECORE_IPC_PUT16(v)\ { \ - *(short *)(ptr) = ECORE_IPC_SWAP2NET16(p->v); \ - ptr += 2; \ + *(short *)(ptr) = ECORE_IPC_SWAP2NET16(p->v); \ + ptr += 2; \ } #define ECORE_IPC_PUT8(v) \ { \ - *(char *)(ptr) = ECORE_IPC_SWAP2NET8(p->v); \ - ptr += 1; \ + *(char *)(ptr) = ECORE_IPC_SWAP2NET8(p->v); \ + ptr += 1; \ } /* padding data */ #define ECORE_IPC_PAD8() ptr += 1 @@ -124,16 +124,16 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); #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; \ - } \ + 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; \ + strcpy((char *)ptr, p->v); \ + ptr += l + 1; \ } /* handy to calculate what sized block we need to alloc */ @@ -143,8 +143,8 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); /* 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_EVAS_LIST_PROTO(x) static Evas_List *x(void *d, int s) -#define ECORE_IPC_ENC_EVAS_LIST_PROTO(x) static void *x(Evas_List *lp, 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 */ @@ -179,9 +179,9 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); /* footer for the hell of it */ #define ECORE_IPC_ENC_STRUCT_FOOT() return d -#define ECORE_IPC_DEC_EVAS_LIST_HEAD(typ) \ +#define ECORE_IPC_DEC_EINA_LIST_HEAD(typ) \ unsigned char *ptr; \ - Evas_List *l; \ + Eina_List *l; \ typ *p; \ l = NULL; \ ptr = d; \ @@ -189,12 +189,12 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); { \ p = malloc(sizeof(typ)); -#define ECORE_IPC_DEC_EVAS_LIST_FOOT() \ - l = evas_list_append(l, p); \ +#define ECORE_IPC_DEC_EINA_LIST_FOOT() \ + l = eina_list_append(l, p); \ } \ return l -#define ECORE_IPC_ENC_EVAS_LIST_HEAD_START(typ) \ - Evas_List *l; \ +#define ECORE_IPC_ENC_EINA_LIST_HEAD_START(typ) \ + Eina_List *l; \ typ *p; \ unsigned char *d, *ptr; \ int len; \ @@ -203,7 +203,7 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); for (l = lp; l; l = l->next) \ { \ p = l->data; -#define ECORE_IPC_ENC_EVAS_LIST_HEAD_FINISH() \ +#define ECORE_IPC_ENC_EINA_LIST_HEAD_FINISH() \ } \ d = malloc(len); \ if(!d) return NULL; \ @@ -213,112 +213,113 @@ EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v); { \ p = l->data; -#define ECORE_IPC_ENC_EVAS_LIST_FOOT() \ +#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 = 16 - } 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; - }; +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; - 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); +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; +}; - /* 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 int ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr); - EAPI Ecore_List *ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr); +struct _Ecore_Ipc_Event_Client_Data +{ + Ecore_Ipc_Client *client; /* 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 char *ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr); - EAPI void ecore_ipc_server_flush(Ecore_Ipc_Server *svr); - + 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 */ - 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 char *ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl); - EAPI void ecore_ipc_client_flush(Ecore_Ipc_Client *cl); + int major; + int minor; + int ref; + int ref_to; + int response; + void *data; + int size; +}; - 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) */ +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 } diff --git a/src/lib/ecore_ipc/Makefile.am b/src/lib/ecore_ipc/Makefile.am index 8dcd9df..60e32d3 100644 --- a/src/lib/ecore_ipc/Makefile.am +++ b/src/lib/ecore_ipc/Makefile.am @@ -7,31 +7,28 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ -I$(top_srcdir)/src/lib/ecore_con \ -I$(top_srcdir)/src/lib/ecore_ipc \ -@SSL_CFLAGS@ - -if BUILD_ECORE_IPC +@EFL_ECORE_IPC_BUILD@ \ +@SSL_CFLAGS@ \ +@EVIL_CFLAGS@ \ +@EINA_CFLAGS@ \ +@WIN32_CPPFLAGS@ lib_LTLIBRARIES = libecore_ipc.la -include_HEADERS = \ -Ecore_Ipc.h +includes_HEADERS = Ecore_Ipc.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_ipc_la_SOURCES = \ -ecore_ipc.c \ -ecore_ipc_private.h +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@ - -libecore_ipc_la_LDFLAGS = -version-info @version_info@ - -libecore_ipc_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_con/libecore_con.la +@SSL_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ \ +@WIN32_LIBS@ -endif +libecore_ipc_la_LDFLAGS = -no-undefined -version-info @version_info@ @release_info@ -EXTRA_DIST = \ -ecore_ipc.c \ -ecore_ipc_private.h +EXTRA_DIST = ecore_ipc_private.h diff --git a/src/lib/ecore_ipc/ecore_ipc.c b/src/lib/ecore_ipc/ecore_ipc.c index 1ea7887..0480001 100644 --- a/src/lib/ecore_ipc/ecore_ipc.c +++ b/src/lib/ecore_ipc/ecore_ipc.c @@ -1,17 +1,31 @@ -#include "Ecore.h" -#include -#include "Ecore_Con.h" -#include "ecore_private.h" -#include "ecore_ipc_private.h" -#include "Ecore_Ipc.h" +#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 @@ -29,7 +43,8 @@ #define DLT_R1 14 #define DLT_R2 15 -/* byte swappers - for dealing with big vs little endian machines */ +int _ecore_ipc_log_dom = -1; + EAPI unsigned short _ecore_ipc_swap_16(unsigned short v) { @@ -75,78 +90,78 @@ _ecore_ipc_dlt_int(int out, int prev, int *mode) /* 0 byte */ if (out == 0) { - *mode = DLT_ZERO; - return 0; + *mode = DLT_ZERO; + return 0; } if (out == (int)0xffffffff) { - *mode = DLT_ONE; - return 0; + *mode = DLT_ONE; + return 0; } if (out == prev) { - *mode = DLT_SAME; - return 0; + *mode = DLT_SAME; + return 0; } if (out == prev << 1) { - *mode = DLT_SHL; - return 0; + *mode = DLT_SHL; + return 0; } if (out == prev >> 1) { - *mode = DLT_SHR; - return 0; + *mode = DLT_SHR; + return 0; } /* 1 byte */ dlt = out - prev; if (!(dlt & 0xffffff00)) { - *mode = DLT_ADD8; - return dlt & 0xff; + *mode = DLT_ADD8; + return dlt & 0xff; } dlt = prev - out; if (!(dlt & 0xffffff00)) { - *mode = DLT_DEL8; - return dlt & 0xff; + *mode = DLT_DEL8; + return dlt & 0xff; } dlt = out - prev; if (!(dlt & 0x00ffffff)) { - *mode = DLT_ADDU8; - return (dlt >> 24) & 0xff; + *mode = DLT_ADDU8; + return (dlt >> 24) & 0xff; } dlt = prev - out; if (!(dlt & 0x00ffffff)) { - *mode = DLT_DELU8; - return (dlt >> 24) & 0xff; + *mode = DLT_DELU8; + return (dlt >> 24) & 0xff; } /* 2 byte */ dlt = out - prev; if (!(dlt & 0xffff0000)) { - *mode = DLT_ADD16; - return dlt & 0xffff; + *mode = DLT_ADD16; + return dlt & 0xffff; } dlt = prev - out; if (!(dlt & 0xffff0000)) { - *mode = DLT_DEL16; - return dlt & 0xffff; + *mode = DLT_DEL16; + return dlt & 0xffff; } dlt = out - prev; if (!(dlt & 0x0000ffff)) { - *mode = DLT_ADDU16; - return (dlt >> 16) & 0xffff; + *mode = DLT_ADDU16; + return (dlt >> 16) & 0xffff; } dlt = prev - out; if (!(dlt & 0x0000ffff)) { - *mode = DLT_DELU16; - return (dlt >> 16) & 0xffff; + *mode = DLT_DELU16; + return (dlt >> 16) & 0xffff; } /* 4 byte */ *mode = DLT_SET; @@ -159,65 +174,65 @@ _ecore_ipc_ddlt_int(int in, int prev, int mode) switch (mode) { case DLT_ZERO: - return 0; - break; + return 0; + break; case DLT_ONE: - return 0xffffffff; - break; + return 0xffffffff; + break; case DLT_SAME: - return prev; - break; + return prev; + break; case DLT_SHL: - return prev << 1; - break; + return prev << 1; + break; case DLT_SHR: - return prev >> 1; - break; + return prev >> 1; + break; case DLT_ADD8: - return prev + in; - break; + return prev + in; + break; case DLT_DEL8: - return prev - in; - break; + return prev - in; + break; case DLT_ADDU8: - return prev + (in << 24); - break; + return prev + (in << 24); + break; case DLT_DELU8: - return prev - (in << 24); - break; + return prev - (in << 24); + break; case DLT_ADD16: - return prev + in; - break; + return prev + in; + break; case DLT_DEL16: - return prev - in; - break; + return prev - in; + break; case DLT_ADDU16: - return prev + (in << 16); - break; + return prev + (in << 16); + break; case DLT_DELU16: - return prev - (in << 16); - break; + return prev - (in << 16); + break; case DLT_SET: - return in; - break; + return in; + break; case DLT_R1: - return 0; - break; + return 0; + break; case DLT_R2: - return 0; - break; + return 0; + break; default: - break; + break; } return 0; } -static int _ecore_ipc_event_client_add(void *data, int ev_type, void *ev); -static int _ecore_ipc_event_client_del(void *data, int ev_type, void *ev); -static int _ecore_ipc_event_server_add(void *data, int ev_type, void *ev); -static int _ecore_ipc_event_server_del(void *data, int ev_type, void *ev); -static int _ecore_ipc_event_client_data(void *data, int ev_type, void *ev); -static int _ecore_ipc_event_server_data(void *data, int ev_type, void *ev); +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); @@ -232,8 +247,8 @@ 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 init_count = 0; -static Ecore_Ipc_Server *servers = NULL; +static int _ecore_ipc_init_count = 0; +static Eina_List *servers = NULL; static Ecore_Event_Handler *handler[6]; /** @@ -253,9 +268,17 @@ ecore_ipc_init(void) { int i = 0; - if (++init_count != 1) return init_count; - - ecore_con_init(); + 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(); @@ -265,18 +288,18 @@ ecore_ipc_init(void) 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); + _ecore_ipc_event_client_add, NULL); handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, - _ecore_ipc_event_client_del, NULL); + _ecore_ipc_event_client_del, NULL); handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, - _ecore_ipc_event_server_add, NULL); + _ecore_ipc_event_server_add, NULL); handler[i++] = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, - _ecore_ipc_event_server_del, NULL); + _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 init_count; + _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; } /** @@ -290,16 +313,21 @@ ecore_ipc_shutdown(void) { int i; - if (--init_count != 0) return init_count; + if (--_ecore_ipc_init_count != 0) + return _ecore_ipc_init_count; - while (servers) ecore_ipc_server_del(servers); + 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(); - - return init_count; + eina_log_domain_unregister(_ecore_ipc_log_dom); + _ecore_ipc_log_dom = -1; + return _ecore_ipc_init_count; } /** @@ -329,6 +357,8 @@ ecore_ipc_server_add(Ecore_Ipc_Type compl_type, const char *name, int port, cons Ecore_Ipc_Type type; Ecore_Con_Type extra = 0; + if (!name) return NULL; + svr = calloc(1, sizeof(Ecore_Ipc_Server)); if (!svr) return NULL; type = compl_type; @@ -337,28 +367,26 @@ ecore_ipc_server_add(Ecore_Ipc_Type compl_type, const char *name, int port, cons switch (type) { case ECORE_IPC_LOCAL_USER: - svr->server = ecore_con_server_add(ECORE_CON_LOCAL_USER | extra, name, port, svr); - break; + 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; + 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; + svr->server = ecore_con_server_add(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr); + break; default: - free(svr); - return NULL; + free(svr); + return NULL; } if (!svr->server) { - free(svr); - return NULL; + free(svr); + return NULL; } svr->max_buf_size = 32 * 1024; svr->data = (void *)data; - svr->client_list = ecore_list_new(); - ecore_list_init(svr->client_list); - servers = _ecore_list2_append(servers, svr); + servers = eina_list_append(servers, svr); ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); return svr; } @@ -386,35 +414,39 @@ ecore_ipc_server_connect(Ecore_Ipc_Type compl_type, char *name, int port, const 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; - type &= ~ECORE_IPC_USE_SSL; - if (compl_type & ECORE_IPC_USE_SSL) extra = ECORE_CON_USE_SSL; + 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; + 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; + 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; + svr->server = ecore_con_server_connect(ECORE_CON_REMOTE_SYSTEM | extra, name, port, svr); + break; default: - free(svr); - return NULL; + free(svr); + return NULL; } if (!svr->server) { - free(svr); - return NULL; + free(svr); + return NULL; } svr->max_buf_size = -1; svr->data = (void *)data; - servers = _ecore_list2_append(servers, svr); + servers = eina_list_append(servers, svr); ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); return svr; } @@ -432,23 +464,27 @@ ecore_ipc_server_del(Ecore_Ipc_Server *svr) if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { - ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, - "ecore_ipc_server_del"); - return NULL; + 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) { - while (svr->clients) - ecore_ipc_client_del((Ecore_Ipc_Client *)svr->clients); - ecore_con_server_del(svr->server); - servers = _ecore_list2_remove(servers, svr); - if (svr->buf) free(svr->buf); - if (svr->client_list) ecore_list_destroy(svr->client_list); - ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE); - free(svr); + 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; } @@ -464,9 +500,9 @@ 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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_get"); + return NULL; } return svr->data; } @@ -474,17 +510,17 @@ ecore_ipc_server_data_get(Ecore_Ipc_Server *svr) /** * Retrieves whether the given IPC server is currently connected. * @param svr The given IPC server. - * @return @c 1 if the server is connected. @c 0 otherwise. + * @return @c EINA_TRUE if the server is connected, @c EINA_FALSE otherwise. * @ingroup Ecore_IPC_Server_Group */ -EAPI int +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 0; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_connected_get"); + return EINA_FALSE; } return ecore_con_server_connected_get(svr->server); } @@ -492,51 +528,51 @@ ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr) /** * Retrieves the list of clients for this server. * @param svr The given IPC server. - * @return An Ecore_List with the clients. + * @return An Eina_List with the clients. * @ingroup Ecore_IPC_Server_Group */ -EAPI Ecore_List * +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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_clients_get"); + return NULL; } - return svr->client_list; + 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; \ + 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; \ + 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; \ + *(dat + s + 0) = (unsigned char)d; \ + s += 1; \ } /** @@ -568,9 +604,9 @@ ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { - ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, - "ecore_ipc_server_send"); - return 0; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_send"); + return 0; } if (size < 0) size = 0; msg.major = major; @@ -627,9 +663,9 @@ ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char { 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_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); } @@ -646,9 +682,9 @@ 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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_size_max_set"); + return; } svr->max_buf_size = size; } @@ -665,9 +701,9 @@ 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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_data_size_max_get"); + return -1; } return svr->max_buf_size; } @@ -682,14 +718,14 @@ ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *svr) * deletion for the @p svr object. If no IP is known NULL is returned. * @ingroup Ecore_Ipc_Server_Group */ -EAPI char * +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; + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_ip_get"); + return NULL; } return ecore_con_server_ip_get(svr->server); } @@ -705,9 +741,9 @@ 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_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, + "ecore_ipc_server_server_flush"); + return; } ecore_con_server_flush(svr->server); } @@ -716,32 +752,32 @@ ecore_ipc_server_flush(Ecore_Ipc_Server *svr) 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; \ + 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; \ + 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; \ + *(dat + s) = (unsigned char)d; \ + s += 1; \ } /** @@ -776,10 +812,12 @@ ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int r if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { - ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, - "ecore_ipc_client_send"); - return 0; + 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; @@ -819,11 +857,11 @@ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_server_get"); + return NULL; } - return (ecore_con_server_data_get(ecore_con_client_server_get(cl->client))); + return cl->svr; } /** @@ -841,21 +879,21 @@ ecore_ipc_client_del(Ecore_Ipc_Client *cl) if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { - ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, - "ecore_ipc_client_del"); - return NULL; + 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 = ecore_con_server_data_get(ecore_con_client_server_get(cl->client)); - ecore_con_client_del(cl->client); - svr->clients = _ecore_list2_remove(svr->clients, cl); - if (cl->buf) free(cl->buf); - ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE); - free(cl); + 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; } @@ -871,9 +909,9 @@ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_set"); + return; } cl->data = (void *)data; } @@ -889,9 +927,9 @@ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_get"); + return NULL; } return cl->data; } @@ -899,7 +937,7 @@ ecore_ipc_client_data_get(Ecore_Ipc_Client *cl) /** * Sets the max data payload size for an Ipc message in bytes * - * @param client The given client. + * @param cl The given client. * @param size The maximum data payload size in bytes. * @ingroup Ecore_Ipc_Client_Group */ @@ -908,18 +946,18 @@ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_size_max_set"); + return; } cl->max_buf_size = size; } /** - * Sets the max data payload size for an Ipc message in bytes + * Gets 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. + * @return The maximum data payload size in bytes on success, @c -1 on failure. * @ingroup Ecore_Ipc_Client_Group */ EAPI int @@ -927,9 +965,9 @@ 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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_data_size_max_get"); + return -1; } return cl->max_buf_size; } @@ -941,17 +979,18 @@ ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl) * @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 NULL is returned. + * deletion for the @p cl object. If no IP is known @c NULL is + * returned. * @ingroup Ecore_Ipc_Client_Group */ -EAPI char * +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; + ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_ip_get"); + return NULL; } return ecore_con_client_ip_get(cl->client); } @@ -967,9 +1006,9 @@ 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_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, + "ecore_ipc_client_flush"); + return; } ecore_con_client_flush(cl->client); } @@ -986,136 +1025,136 @@ ecore_ipc_ssl_available_get(void) } -static int +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; - if (!_ecore_list2_find(servers, ecore_con_server_data_get(ecore_con_client_server_get(e->client)))) return 1; + 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_Server *svr; - - cl = calloc(1, sizeof(Ecore_Ipc_Client)); - if (!cl) return 0; - svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client)); - 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 = _ecore_list2_append(svr->clients, cl); - ecore_list_append(svr->client_list, cl); - if (!cl->delete_me) - { - Ecore_Ipc_Event_Client_Add *e2; - - e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Add)); - if (e2) - { + 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); - } - } + e2->client = cl; + ecore_event_add(ECORE_IPC_EVENT_CLIENT_ADD, e2, + _ecore_ipc_event_client_add_free, NULL); + } + } } - return 0; + return ECORE_CALLBACK_CANCEL; } -static int +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 (!_ecore_list2_find(servers, ecore_con_server_data_get(ecore_con_client_server_get(e->client)))) return 1; + 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); - { - Ecore_Ipc_Event_Client_Del *e2; - Ecore_Ipc_Server *svr; - - svr = ecore_con_server_data_get(ecore_con_client_server_get(e->client)); - ecore_list_goto(svr->client_list, cl); - ecore_list_remove(svr->client_list); - ecore_list_first_goto(svr->client_list); - 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); - } - } - } + 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 0; + return ECORE_CALLBACK_CANCEL; } -static int +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 (!_ecore_list2_find(servers, ecore_con_server_data_get(e->server))) return 1; + 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_Server *svr; - svr = ecore_con_server_data_get(e->server); - if (!svr->delete_me) - { - Ecore_Ipc_Event_Server_Add *e2; + 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) - { + 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); - } - } + e2->server = svr; + ecore_event_add(ECORE_IPC_EVENT_SERVER_ADD, e2, + _ecore_ipc_event_server_add_free, NULL); + } + } } - return 0; + return ECORE_CALLBACK_CANCEL; } -static int +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 (!_ecore_list2_find(servers, ecore_con_server_data_get(e->server))) return 1; + 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_Server *svr; - svr = ecore_con_server_data_get(e->server); - if (!svr->delete_me) - { - Ecore_Ipc_Event_Server_Del *e2; + 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) - { + 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); - } - } + e2->server = svr; + ecore_event_add(ECORE_IPC_EVENT_SERVER_DEL, e2, + _ecore_ipc_event_server_del_free, NULL); + } + } } - return 0; + return ECORE_CALLBACK_CANCEL; } #define CLSZ(_n) \ @@ -1128,186 +1167,186 @@ _ecore_ipc_event_server_del(void *data __UNUSED__, int ev_type __UNUSED__, void 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; \ + 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; \ + 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; \ + 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 int +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; - if (!_ecore_list2_find(servers, ecore_con_server_data_get(ecore_con_client_server_get(e->client)))) return 1; + 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 0; - } - 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 0; - } - - 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; - Ecore_Ipc_Server *svr; - int max, max2; - - buf = NULL; - svr = ecore_con_server_data_get(ecore_con_client_server_get(cl->client)); - 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 0; - 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 0; - } - 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 0; - } - memcpy(buf, cl->buf + offset, cl->buf_size - offset); - free(cl->buf); - cl->buf = buf; - cl->buf_size -= offset; - } + 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 0; + return ECORE_CALLBACK_CANCEL; } #define SVSZ(_n) \ @@ -1320,175 +1359,175 @@ _ecore_ipc_event_client_data(void *data __UNUSED__, int ev_type __UNUSED__, void 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; \ + 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; \ + 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; \ + 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 int +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 (!_ecore_list2_find(servers, ecore_con_server_data_get(e->server))) return 1; + 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 0; - } - 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 0; - } - - 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 0; - 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 0; - } - 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 0; - } - memcpy(buf, svr->buf + offset, svr->buf_size - offset); - free(svr->buf); - svr->buf = buf; - svr->buf_size -= offset; - } + 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 0; + return ECORE_CALLBACK_CANCEL; } static void diff --git a/src/lib/ecore_ipc/ecore_ipc_private.h b/src/lib/ecore_ipc/ecore_ipc_private.h index 2eb6f98..bedaab1 100644 --- a/src/lib/ecore_ipc/ecore_ipc_private.h +++ b/src/lib/ecore_ipc/ecore_ipc_private.h @@ -1,19 +1,54 @@ #ifndef _ECORE_IPC_PRIVATE_H #define _ECORE_IPC_PRIVATE_H -#include "Ecore_Data.h" -#if USE_OPENSSL -#include +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_Client Ecore_Ipc_Client; -typedef struct _Ecore_Ipc_Server Ecore_Ipc_Server; 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 @@ -26,20 +61,16 @@ struct _Ecore_Ipc_Msg_Head int ref_to; int response; int size; -} -#ifdef _GNU_C_ -__attribute__ ((packed)); -#endif -; +} ECORE_IPC_STRUCT_PACKED; #ifdef __sgi #pragma pack 0 #endif struct _Ecore_Ipc_Client { - Ecore_List __list_data; ECORE_MAGIC; Ecore_Con_Client *client; + Ecore_Ipc_Server *svr; void *data; unsigned char *buf; int buf_size; @@ -55,11 +86,9 @@ struct _Ecore_Ipc_Client struct _Ecore_Ipc_Server { - Ecore_List __list_data; ECORE_MAGIC; Ecore_Con_Server *server; - Ecore_Ipc_Client *clients; - Ecore_List *client_list; + Eina_List *clients; void *data; unsigned char *buf; int buf_size; 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 index ea81358..359e974 100644 --- a/src/lib/ecore_sdl/Ecore_Sdl.h +++ b/src/lib/ecore_sdl/Ecore_Sdl.h @@ -1,7 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef _ECORE_SDL_H #define _ECORE_SDL_H @@ -40,77 +36,71 @@ extern "C" { #endif -EAPI extern int ECORE_SDL_EVENT_KEY_DOWN; /**< SDL Key Down event */ -EAPI extern int ECORE_SDL_EVENT_KEY_UP; /**< SDL Key Up event */ -EAPI extern int ECORE_SDL_EVENT_MOUSE_BUTTON_DOWN; /**< SDL Mouse Down event */ -EAPI extern int ECORE_SDL_EVENT_MOUSE_BUTTON_UP; /**< SDL Mouse Up event */ -EAPI extern int ECORE_SDL_EVENT_MOUSE_MOVE; /**< SDL Mouse Move event */ -EAPI extern int ECORE_SDL_EVENT_MOUSE_WHEEL; /**< SDL Mouse Wheel event */ -EAPI extern int ECORE_SDL_EVENT_GOT_FOCUS; /**< SDL Mouse Wheel event */ -EAPI extern int ECORE_SDL_EVENT_LOST_FOCUS; /**< SDL Mouse Wheel event */ +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; + 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; + 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; + 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; + 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; + 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; + 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; + int w; + int h; }; EAPI int ecore_sdl_init(const char *name); diff --git a/src/lib/ecore_sdl/Ecore_Sdl_Keys.h b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h index 8e5a7a0..4d0b60b 100644 --- a/src/lib/ecore_sdl/Ecore_Sdl_Keys.h +++ b/src/lib/ecore_sdl/Ecore_Sdl_Keys.h @@ -11,13 +11,15 @@ struct _ecore_sdl_keys_s static const struct _ecore_sdl_keys_s keystable[] = { { SDLK_UNKNOWN, "0x00", "" }, - { SDLK_FIRST, "First", "" }, +#ifndef BUILD_ECORE_EVAS_SDL_130 + { SDLK_FIRST, "First", "First" }, +#endif { SDLK_BACKSPACE, "BackSpace", "\010" }, { SDLK_TAB, "Tab", "\011" }, - { SDLK_CLEAR, "Clear", "" }, + { SDLK_CLEAR, "Clear", "Clear" }, { SDLK_RETURN, "Return", "\015" }, - { SDLK_PAUSE, "Pause", "" }, - { SDLK_ESCAPE, "Escape", "" }, + { SDLK_PAUSE, "Pause", "Pause" }, + { SDLK_ESCAPE, "Escape", "\033" }, { SDLK_SPACE, "space", " " }, { SDLK_EXCLAIM, "exclam", "!" }, { SDLK_QUOTEDBL, "quotedbl", "\"" }, @@ -27,7 +29,7 @@ static const struct _ecore_sdl_keys_s keystable[] = { SDLK_QUOTE, "apostrophe", "'" }, { SDLK_LEFTPAREN, "parenleft", "(" }, { SDLK_RIGHTPAREN, "parenright", ")" }, - { SDLK_ASTERISK, "asterik", "*" }, + { SDLK_ASTERISK, "asterisk", "*" }, { SDLK_PLUS, "plus", "+" }, { SDLK_COMMA, "comma", "," }, { SDLK_MINUS, "minus", "-" }, @@ -43,7 +45,7 @@ static const struct _ecore_sdl_keys_s keystable[] = { SDLK_7, "7", "7" }, { SDLK_8, "8", "8" }, { SDLK_9, "9", "9" }, - { SDLK_COLON, "colon", ";" }, + { SDLK_COLON, "colon", ":" }, { SDLK_SEMICOLON, "semicolon", ";" }, { SDLK_LESS, "less", "<" }, { SDLK_EQUALS, "equal", "=" }, @@ -87,6 +89,7 @@ static const struct _ecore_sdl_keys_s keystable[] = { 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", "" }, @@ -184,7 +187,7 @@ static const struct _ecore_sdl_keys_s keystable[] = { SDLK_WORLD_93, "w93", "" }, { SDLK_WORLD_94, "w94", "" }, { SDLK_WORLD_95, "w95", "" }, - +#endif /* Numeric keypad */ { SDLK_KP0, "KP0", "0" }, { SDLK_KP1, "KP1", "1" }, @@ -205,59 +208,59 @@ static const struct _ecore_sdl_keys_s keystable[] = { SDLK_KP_EQUALS, "KP_Equals", "=" }, /* Arrows + Home/End pad */ - { SDLK_UP, "Up", "" }, - { SDLK_DOWN, "Down", "" }, - { SDLK_RIGHT, "Right", "" }, - { SDLK_LEFT, "Left", "" }, - { SDLK_INSERT, "Insert", "" }, - { SDLK_HOME, "Home", "" }, - { SDLK_END, "End", "" }, - { SDLK_PAGEUP, "Page_Up", "" }, - { SDLK_PAGEDOWN, "Page_Down", "" }, + { 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", "" }, - { SDLK_F2, "F2", "" }, - { SDLK_F3, "F3", "" }, - { SDLK_F4, "F4", "" }, - { SDLK_F5, "F5", "" }, - { SDLK_F6, "F6", "" }, - { SDLK_F7, "F7", "" }, - { SDLK_F8, "F8", "" }, - { SDLK_F9, "F9", "" }, - { SDLK_F10, "F10", "" }, - { SDLK_F11, "F11", "" }, - { SDLK_F12, "F12", "" }, - { SDLK_F13, "F13", "" }, - { SDLK_F14, "F14", "" }, - { SDLK_F15, "F15", "" }, + { 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", "" }, - { SDLK_CAPSLOCK, "Caps_Lock", "" }, - { SDLK_SCROLLOCK, "Scroll_Lock", "" }, - { SDLK_RSHIFT, "Shift_R", "" }, - { SDLK_LSHIFT, "Shift_L", "" }, - { SDLK_RCTRL, "Control_R", "" }, - { SDLK_LCTRL, "Control_L", "" }, - { SDLK_RALT, "Alt_R", "" }, - { SDLK_LALT, "Alt_L", "" }, - { SDLK_RMETA, "Meta_R", "" }, - { SDLK_LMETA, "Meta_L", "" }, - { SDLK_LSUPER, "Super_L", "" }, /* Left "Windows" key */ - { SDLK_RSUPER, "Super_R", "" }, /* Right "Windows" key */ - { SDLK_MODE, "Mode", "" }, /* "Alt Gr" key */ - { SDLK_COMPOSE, "Compose", "" }, /* Multi-key compose key */ + { 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", "" }, - { SDLK_PRINT, "Print", "" }, - { SDLK_SYSREQ, "SysReq", "" }, - { SDLK_BREAK, "Break", "" }, - { SDLK_MENU, "Menu", "" }, - { SDLK_POWER, "Power", "" }, /* Power Macintosh power key */ - { SDLK_EURO, "Euro", "" }, /* Some european keyboards */ - { SDLK_UNDO, "Undo", "" } /* Atari keyboard has Undo */ + { 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 index 6dd931e..27210bb 100644 --- a/src/lib/ecore_sdl/Makefile.am +++ b/src/lib/ecore_sdl/Makefile.am @@ -2,31 +2,28 @@ 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 \ -@SDL_CFLAGS@ - -if BUILD_ECORE_SDL +-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 -include_HEADERS = \ -Ecore_Sdl.h +includes_HEADERS = Ecore_Sdl.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_sdl_la_SOURCES = \ -ecore_sdl.c \ -Ecore_Sdl_Keys.h +ecore_sdl.c libecore_sdl_la_LIBADD = \ $(top_builddir)/src/lib/ecore/libecore.la \ -@SDL_LIBS@ - -libecore_sdl_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@SDL_LIBS@ @EVIL_LIBS@ @EINA_LIBS@ -libecore_sdl_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la +libecore_sdl_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ -endif - -EXTRA_DIST = \ -Ecore_Sdl.h \ -Ecore_Sdl_Keys.h \ -ecore_sdl.c +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 index 2d9d316..3f28216 100644 --- a/src/lib/ecore_sdl/ecore_sdl.c +++ b/src/lib/ecore_sdl/ecore_sdl.c @@ -1,28 +1,58 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + #include +#include "Eina.h" #include "Ecore_Sdl.h" -#include "ecore_private.h" +#include "Ecore_Input.h" #include "Ecore.h" -#include "Ecore_Data.h" +#include "ecore_sdl_private.h" +#include "ecore_private.h" #include "Ecore_Sdl_Keys.h" -EAPI int ECORE_SDL_EVENT_KEY_DOWN = 0; -EAPI int ECORE_SDL_EVENT_KEY_UP = 0; -EAPI int ECORE_SDL_EVENT_MOUSE_BUTTON_DOWN = 0; -EAPI int ECORE_SDL_EVENT_MOUSE_BUTTON_UP = 0; -EAPI int ECORE_SDL_EVENT_MOUSE_MOVE = 0; -EAPI int ECORE_SDL_EVENT_MOUSE_WHEEL = 0; +#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 Framebuffer Library Functions + * @defgroup Ecore_Sdl_Library_Group SDL Library Functions * - * Functions used to set up and shut down the Ecore_Framebuffer functions. + * Functions used to set up and shut down the Ecore_Sdl functions. */ /** @@ -35,20 +65,26 @@ static int _ecore_sdl_init_count = 0; EAPI int ecore_sdl_init(const char *name __UNUSED__) { - if(!_ecore_sdl_init_count) - { - ECORE_SDL_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_SDL_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_SDL_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_SDL_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_SDL_EVENT_MOUSE_MOVE = ecore_event_type_new(); - ECORE_SDL_EVENT_MOUSE_WHEEL = ecore_event_type_new(); - 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(); - } - return ++_ecore_sdl_init_count; + 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; } /** @@ -60,8 +96,59 @@ ecore_sdl_init(const char *name __UNUSED__) EAPI int ecore_sdl_shutdown(void) { - _ecore_sdl_init_count--; - return _ecore_sdl_init_count; + 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 @@ -77,14 +164,27 @@ ecore_sdl_feed_events(void) { case SDL_MOUSEMOTION: { - Ecore_Sdl_Event_Mouse_Move *ev; + Ecore_Event_Mouse_Move *ev; - ev = malloc(sizeof(Ecore_Sdl_Event_Mouse_Move)); + 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->time = time; + 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_SDL_EVENT_MOUSE_MOVE, ev, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL); break; } case SDL_MOUSEBUTTONDOWN: @@ -92,46 +192,66 @@ ecore_sdl_feed_events(void) if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) { - Ecore_Sdl_Event_Mouse_Wheel *ev; + Ecore_Event_Mouse_Wheel *ev; + + ev = malloc(sizeof(Ecore_Event_Mouse_Wheel)); + if (!ev) return ; - ev = malloc(sizeof (Ecore_Sdl_Event_Mouse_Wheel)); - ev->x = event.button.x; - ev->y = event.button.y; + ev->timestamp = time; + ev->window = 0; + ev->event_window = 0; + ev->modifiers = 0; /* FIXME: keep modifier around. */ ev->direction = 0; - ev->wheel = event.button.button == SDL_BUTTON_WHEELDOWN ? -1 : 1; - ev->time = time; + ev->z = event.button.button == SDL_BUTTON_WHEELDOWN ? -1 : 1; - ecore_event_add(ECORE_SDL_EVENT_MOUSE_WHEEL, ev, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, ev, NULL, NULL); } else { - Ecore_Sdl_Event_Mouse_Button_Down *ev; + Ecore_Event_Mouse_Button *ev; - ev = malloc(sizeof (Ecore_Sdl_Event_Mouse_Button_Down)); - ev->x = event.button.x; - ev->y = event.button.y; - ev->button = event.button.button; + 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; - ev->time = time; - ecore_event_add(ECORE_SDL_EVENT_MOUSE_BUTTON_DOWN, ev, NULL, NULL); + /* 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_Sdl_Event_Mouse_Button_Up *ev; + Ecore_Event_Mouse_Button *ev; - ev = malloc(sizeof (Ecore_Sdl_Event_Mouse_Button_Up)); - ev->x = event.button.x; - ev->y = event.button.y; - ev->button = event.button.button; + 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; - ev->time = time; - ecore_event_add(ECORE_SDL_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL); + /* 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: @@ -154,44 +274,48 @@ ecore_sdl_feed_events(void) case SDL_KEYDOWN: { - Ecore_Sdl_Event_Key_Down *ev; - unsigned int i; + 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 = malloc(sizeof (Ecore_Sdl_Event_Key_Down)); - ev->time = time; + ev = _ecore_sdl_event_key(&event, time); + if (ev) ecore_event_add(ECORE_EVENT_KEY_DOWN, ev, NULL, 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->keycompose = keystable[i].compose; + if (!entry) + { + entry = malloc(sizeof (Ecore_SDL_Pressed)); + if (!entry) break; - ecore_event_add(ECORE_SDL_EVENT_KEY_DOWN, ev, NULL, NULL); - return ; - } + entry->key = event.key.keysym.sym; - free(ev); + 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_Sdl_Event_Key_Up *ev; - unsigned int i; - - ev = malloc(sizeof (Ecore_Sdl_Event_Key_Up)); - ev->time = time; + Ecore_Event_Key *ev; + Ecore_SDL_Pressed *entry; - 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->keycompose = keystable[i].compose; - - ecore_event_add(ECORE_SDL_EVENT_KEY_UP, ev, NULL, NULL); - return ; - } + 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); + } - free(ev); + ev = _ecore_sdl_event_key(&event, time); + if (ev) ecore_event_add(ECORE_EVENT_KEY_UP, ev, NULL, NULL); break; } case SDL_ACTIVEEVENT: 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..8cd0f9d --- /dev/null +++ b/src/lib/ecore_wayland/Ecore_Wayland.h @@ -0,0 +1,391 @@ +#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; + + Eina_Bool frame_pending; + struct wl_callback *frame_callback; + /* 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..54c77d0 --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_input.c @@ -0,0 +1,1207 @@ +#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 + +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 |= ECORE_EVENT_MODIFIER_CTRL; + if (mask & input->xkb.alt_mask) + input->modifiers |= ECORE_EVENT_MODIFIER_ALT; + if (mask & input->xkb.shift_mask) + input->modifiers |= ECORE_EVENT_MODIFIER_SHIFT; + + 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 index 6c9e4a0..ae1bd4e 100644 --- a/src/lib/ecore_win32/Ecore_Win32.h +++ b/src/lib/ecore_win32/Ecore_Win32.h @@ -1,10 +1,22 @@ +#ifndef __ECORE_WIN32_H__ +#define __ECORE_WIN32_H__ + /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND + * THE API MAY CHANGE. */ -#ifndef __ECORE_WIN32_H__ -#define __ECORE_WIN32_H__ +#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 @@ -33,281 +45,336 @@ #endif /* ! _WIN32 */ -typedef void Ecore_Win32_Window; -typedef void Ecore_Win32_Cursor; +#ifdef __cplusplus +extern "C" { +#endif -/* Window state */ +/** + * @defgroup Ecore_Win32_Group Ecore_Win32 library + * + * @{ + */ +/** + * @typedef Ecore_Win32_Window_State + * State of a window. + */ typedef enum { - /* The window is iconified. */ - ECORE_WIN32_WINDOW_STATE_ICONIFIED, - /* The window is a modal dialog box. */ - ECORE_WIN32_WINDOW_STATE_MODAL, - /* The window manager should keep the window's position fixed - * even if the virtual desktop scrolls. */ - ECORE_WIN32_WINDOW_STATE_STICKY, - /* The window has the maximum vertical size. */ - ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT, - /* The window has the maximum horizontal size. */ - ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ, - /* The window has the maximum horizontal and vertical size. */ - ECORE_WIN32_WINDOW_STATE_MAXIMIZED, - /* The window is shaded. */ - ECORE_WIN32_WINDOW_STATE_SHADED, - /* The window is invisible (i.e. minimized/iconified) */ - ECORE_WIN32_WINDOW_STATE_HIDDEN, - /* The window should fill the entire screen and have no - * window border/decorations */ - ECORE_WIN32_WINDOW_STATE_FULLSCREEN, - /* The following are not documented because they are not - * intended for use in applications. */ - ECORE_WIN32_WINDOW_STATE_ABOVE, - ECORE_WIN32_WINDOW_STATE_BELOW, - /* FIXME: Documentation */ - ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION, - /* Unknown state */ - ECORE_WIN32_WINDOW_STATE_UNKNOWN + 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; -/* Window type */ - +/** + * @typedef Ecore_Win32_Window_Type + * Type of a window. + */ typedef enum { - /* Desktop feature*/ - ECORE_WIN32_WINDOW_TYPE_DESKTOP, - /* Dock window (should be on top of other windows */ - ECORE_WIN32_WINDOW_TYPE_DOCK, - /* Toolbar window */ - ECORE_WIN32_WINDOW_TYPE_TOOLBAR, - /* Menu window */ - ECORE_WIN32_WINDOW_TYPE_MENU, - /* Small persistent utility window, such as a palette or toolbox */ - ECORE_WIN32_WINDOW_TYPE_UTILITY, - /* Splash screen window displayed as an application is starting up */ - ECORE_WIN32_WINDOW_TYPE_SPLASH, - /* Dialog window */ - ECORE_WIN32_WINDOW_TYPE_DIALOG, - /* Normal top-level window */ - ECORE_WIN32_WINDOW_TYPE_NORMAL, - /* Unknown type */ - ECORE_WIN32_WINDOW_TYPE_UNKNOWN + 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; -/*cursor shapes */ - +/** + * @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_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; -/* Events */ +/** + * @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 struct _Ecore_Win32_Event_Key_Down Ecore_Win32_Event_Key_Down; -typedef struct _Ecore_Win32_Event_Key_Up Ecore_Win32_Event_Key_Up; -typedef struct _Ecore_Win32_Event_Mouse_Button_Down Ecore_Win32_Event_Mouse_Button_Down; -typedef struct _Ecore_Win32_Event_Mouse_Button_Up Ecore_Win32_Event_Mouse_Button_Up; -typedef struct _Ecore_Win32_Event_Mouse_Move Ecore_Win32_Event_Mouse_Move; +/** + * @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 struct _Ecore_Win32_Event_Mouse_Wheel Ecore_Win32_Event_Mouse_Wheel; + +/** + * @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 struct _Ecore_Win32_Event_Window_Hide Ecore_Win32_Event_Window_Hide; -typedef struct _Ecore_Win32_Event_Window_Show Ecore_Win32_Event_Window_Show; -typedef struct _Ecore_Win32_Event_Window_Configure Ecore_Win32_Event_Window_Configure; -typedef struct _Ecore_Win32_Event_Window_Resize Ecore_Win32_Event_Window_Resize; -typedef struct _Ecore_Win32_Event_Window_Delete_Request Ecore_Win32_Event_Window_Delete_Request; -struct _Ecore_Win32_Event_Key_Down -{ - Ecore_Win32_Window *window; - char *keyname; - char *keysymbol; - char *keycompose; - double time; -}; +/** + * @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; -struct _Ecore_Win32_Event_Key_Up -{ - Ecore_Win32_Window *window; - char *keyname; - char *keysymbol; - char *keycompose; - double time; -}; +/** + * @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; -struct _Ecore_Win32_Event_Mouse_Button_Down -{ - Ecore_Win32_Window *window; - int button; - int x; - int y; - double time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; +/** + * @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; -struct _Ecore_Win32_Event_Mouse_Button_Up -{ - Ecore_Win32_Window *window; - int button; - int x; - int y; - double time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; +/** + * @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; -struct _Ecore_Win32_Event_Mouse_Move -{ - Ecore_Win32_Window *window; - int x; - int y; - double time; -}; +/** + * @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; - int x; - int y; - double time; + 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; - int x; - int y; - double time; -}; - -struct _Ecore_Win32_Event_Mouse_Wheel -{ - Ecore_Win32_Window *window; - int direction; /* 0 = default up/down wheel FIXME: more wheel types */ - int z; /* ...,-2,-1 = down, 1,2,... = up */ - int modifiers; - int x; - int y; - double time; + 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; - double time; + 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; - double time; + 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; - int x; - int y; - int width; - int height; - double time; + 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; - double time; + 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; - double time; + 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; - double time; + 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; - double time; + 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; + Ecore_Win32_Window *window; /**< The window that received the event */ Ecore_Win32_Window *abovewin; - int x; - int y; - int width; - int height; - double time; + 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; - int width; - int height; - double time; + 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; - double time; + Ecore_Win32_Window *window; /**< The window that received the event */ + unsigned long timestamp; /**< The time the event occurred */ }; -EAPI extern int ECORE_WIN32_EVENT_KEY_DOWN; -EAPI extern int ECORE_WIN32_EVENT_KEY_UP; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_BUTTON_DOWN; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_BUTTON_UP; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_MOVE; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_IN; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_OUT; -EAPI extern int ECORE_WIN32_EVENT_MOUSE_WHEEL; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_IN; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_FOCUS_OUT; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_DAMAGE; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_CREATE; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_DESTROY; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_HIDE; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_SHOW; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_CONFIGURE; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_RESIZE; -EAPI extern int ECORE_WIN32_EVENT_WINDOW_DELETE_REQUEST; +/** + * @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 double ecore_win32_current_time_get(void); -EAPI void ecore_win32_message_loop_begin (void); +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 */ @@ -322,7 +389,7 @@ EAPI Ecore_Win32_Window *ecore_win32_window_override_new(Ecore_Win32_Window *par int width, int height); -EAPI void ecore_win32_window_del(Ecore_Win32_Window *window); +EAPI void ecore_win32_window_free(Ecore_Win32_Window *window); EAPI void *ecore_win32_window_hwnd_get(Ecore_Win32_Window *window); @@ -393,16 +460,18 @@ 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_set(Ecore_Win32_Window *window); +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, - int on); + Eina_Bool on); EAPI void ecore_win32_window_borderless_set(Ecore_Win32_Window *window, - int on); + Eina_Bool on); EAPI void ecore_win32_window_fullscreen_set(Ecore_Win32_Window *window, - int on); + Eina_Bool on); EAPI void ecore_win32_window_cursor_set(Ecore_Win32_Window *window, Ecore_Win32_Cursor *cursor); @@ -429,9 +498,29 @@ EAPI Ecore_Win32_Cursor *ecore_win32_cursor_new(const void *pixels_and, EAPI void ecore_win32_cursor_free(Ecore_Win32_Cursor *cursor); -EAPI Ecore_Win32_Cursor *ecore_win32_cursor_shape_get(Ecore_Win32_Cursor_Shape shape); +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); + + -EAPI int ecore_win32_cursor_size_get(void); +/* 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 index 1795c69..7031fa5 100644 --- a/src/lib/ecore_win32/Makefile.am +++ b/src/lib/ecore_win32/Makefile.am @@ -2,30 +2,43 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_builddir)/src/lib/ecore - - -if BUILD_ECORE_WIN32 +-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 -include_HEADERS = \ -Ecore_Win32.h +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 - -libecore_win32_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +$(top_builddir)/src/lib/ecore/libecore.la \ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ \ +@EVIL_LIBS@ -endif +libecore_win32_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ EXTRA_DIST = \ -ecore_win32_private.h +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 index 2acc005..b571d74 100644 --- a/src/lib/ecore_win32/ecore_win32.c +++ b/src/lib/ecore_win32/ecore_win32.c @@ -1,199 +1,61 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif #include -#include /* for printf */ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN #include -#include "Ecore.h" +#include +#include +#include + #include "Ecore_Win32.h" #include "ecore_win32_private.h" +/*============================================================================* + * Local * + *============================================================================*/ -/***** Global declarations *****/ +/** + * @cond LOCAL + */ -HINSTANCE _ecore_win32_instance = NULL; -double _ecore_win32_double_click_time = 0.25; -double _ecore_win32_event_last_time = 0.0; -Ecore_Win32_Window *_ecore_win32_event_last_window = NULL; +/* OLE IID for Drag'n Drop */ -int ECORE_WIN32_EVENT_KEY_DOWN = 0; -int ECORE_WIN32_EVENT_KEY_UP = 0; -int ECORE_WIN32_EVENT_MOUSE_BUTTON_DOWN = 0; -int ECORE_WIN32_EVENT_MOUSE_BUTTON_UP = 0; -int ECORE_WIN32_EVENT_MOUSE_MOVE = 0; -int ECORE_WIN32_EVENT_MOUSE_IN = 0; -int ECORE_WIN32_EVENT_MOUSE_OUT = 0; -int ECORE_WIN32_EVENT_MOUSE_WHEEL = 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; +# 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); - -/***** Private declarations *****/ +#define IDI_ICON 101 static int _ecore_win32_init_count = 0; -LRESULT CALLBACK _ecore_win32_window_procedure(HWND window, - UINT message, - WPARAM window_param, - LPARAM data_param); - - -/***** API *****/ - - -int -ecore_win32_init() +static void +_ecore_win32_size_check(Ecore_Win32_Window *win, int w, int h, int *dx, int *dy) { - WNDCLASS wc; - - if (_ecore_win32_init_count > 0) - { - _ecore_win32_init_count++; - return _ecore_win32_init_count; - } - - printf (" *** ecore_win32_init\n"); - _ecore_win32_instance = GetModuleHandle(NULL); - if (!_ecore_win32_instance) - return 0; - - memset (&wc, 0, sizeof (WNDCLASS)); - 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 = LoadIcon (NULL, IDI_APPLICATION); - wc.hCursor = LoadCursor (NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE); - wc.lpszMenuName = NULL; - wc.lpszClassName = ECORE_WIN32_WINDOW_CLASS; - - if(!RegisterClass(&wc)) - { - FreeLibrary(_ecore_win32_instance); - return 0; - } - - if (!ECORE_WIN32_EVENT_KEY_DOWN) - { - ECORE_WIN32_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_WIN32_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_MOVE = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_IN = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_OUT = ecore_event_type_new(); - ECORE_WIN32_EVENT_MOUSE_WHEEL = 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(); - } - - _ecore_win32_init_count++; - - return _ecore_win32_init_count; + 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; } -int -ecore_win32_shutdown() -{ - _ecore_win32_init_count++; - if (_ecore_win32_init_count > 0) return _ecore_win32_init_count; - if (!_ecore_win32_instance) return _ecore_win32_init_count; - - UnregisterClass(ECORE_WIN32_WINDOW_CLASS, _ecore_win32_instance); - FreeLibrary(_ecore_win32_instance); - _ecore_win32_instance = NULL; - - if (_ecore_win32_init_count < 0) _ecore_win32_init_count = 0; - - return _ecore_win32_init_count; -} - -int -ecore_win32_screen_depth_get() -{ - HDC dc; - int depth; - - dc = GetDC(NULL); - if (!dc) - return 0; - - depth = GetDeviceCaps(dc, BITSPIXEL); - ReleaseDC(NULL, dc); - - return depth; -} - -/** - * 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 - */ -void -ecore_win32_double_click_time_set(double t) -{ - if (t < 0.0) t = 0.0; - _ecore_win32_double_click_time = t; -} - -/** - * Retrieves the double and triple click flag timeout. - * - * See @ref ecore_win32_double_click_time_set for more information. - * - * @return The timeout for double clicks in seconds. - */ -double -ecore_win32_double_click_time_get(void) -{ - return _ecore_win32_double_click_time; -} - -/** - * Return the last event time - */ -double -ecore_win32_current_time_get(void) -{ - return _ecore_win32_event_last_time; -} - - -/***** Private functions definitions *****/ - - LRESULT CALLBACK _ecore_win32_window_procedure(HWND window, UINT message, @@ -201,7 +63,7 @@ _ecore_win32_window_procedure(HWND window, LPARAM data_param) { Ecore_Win32_Callback_Data *data; - POINTS pt; + POINTS point; DWORD coord; data = (Ecore_Win32_Callback_Data *)malloc(sizeof(Ecore_Win32_Callback_Data)); @@ -211,121 +73,342 @@ _ecore_win32_window_procedure(HWND window, data->message = message; data->window_param = window_param; data->data_param = data_param; - data->time = GetMessageTime(); + data->timestamp = GetMessageTime(); coord = GetMessagePos(); - pt = MAKEPOINTS(coord); - data->x = pt.x; - data->y = pt.y; + 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: - printf (" * ecore message : keystroke down\n"); + 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: - printf (" * ecore message : keystroke up\n"); - _ecore_win32_event_handle_key_release(data, 1); + 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: - printf (" * ecore message : focus in\n"); + INF("setfocus message"); _ecore_win32_event_handle_focus_in(data); return 0; case WM_KILLFOCUS: - printf (" * ecore message : focus out\n"); + INF("kill focus message"); _ecore_win32_event_handle_focus_out(data); return 0; /* Mouse input notifications */ case WM_LBUTTONDOWN: - printf (" * ecore message : lbuttondown\n"); + INF("left button down message"); + SetCapture(window); _ecore_win32_event_handle_button_press(data, 1); return 0; case WM_MBUTTONDOWN: - printf (" * ecore message : mbuttondown\n"); + INF("middle button down message"); _ecore_win32_event_handle_button_press(data, 2); return 0; case WM_RBUTTONDOWN: - printf (" * ecore message : rbuttondown\n"); + INF("right button down message"); _ecore_win32_event_handle_button_press(data, 3); return 0; case WM_LBUTTONUP: - printf (" * ecore message : lbuttonup\n"); - _ecore_win32_event_handle_button_release(data, 1); - return 0; + { + 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: - printf (" * ecore message : mbuttonup\n"); + INF("middle button up message"); _ecore_win32_event_handle_button_release(data, 2); return 0; case WM_RBUTTONUP: - printf (" * ecore message : rbuttonup\n"); + INF("right button up message"); _ecore_win32_event_handle_button_release(data, 3); return 0; case WM_MOUSEMOVE: { - RECT rect; - struct _Ecore_Win32_Window *w = NULL; - - w = (struct _Ecore_Win32_Window *)GetWindowLong(window, GWL_USERDATA); + 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; - - 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); - } - - } - } + { + 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: - printf (" * ecore message : mouse wheel\n"); + INF("mouse wheel message"); _ecore_win32_event_handle_button_press(data, 4); return 0; /* Window notifications */ case WM_CREATE: - { - RECT rect; - GetClientRect(window, &rect); - printf (" *** ecore message : create %ld %ld\n", - rect.right - rect.left, rect.bottom - rect.top); - } + INF("create window message"); _ecore_win32_event_handle_create_notify(data); return 0; case WM_DESTROY: - printf (" * ecore message : destroy\n"); + INF("destroy window message"); _ecore_win32_event_handle_destroy_notify(data); return 0; case WM_SHOWWINDOW: - { - RECT rect; - GetClientRect(window, &rect); - printf (" *** ecore message : show %ld %ld\n", - rect.right - rect.left, rect.bottom - rect.top); - } + INF("show window message"); if ((data->data_param == SW_OTHERUNZOOM) || - (data->data_param == SW_OTHERUNZOOM)) + (data->data_param == SW_OTHERZOOM)) return 0; if (data->window_param) @@ -335,22 +418,26 @@ _ecore_win32_window_procedure(HWND window, return 0; case WM_CLOSE: - printf (" * ecore message : close\n"); + 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: - printf (" * ecore message : moving\n"); + INF("moving window message"); + _ecore_win32_event_handle_configure_notify(data); return TRUE; case WM_MOVE: - printf (" * ecore message : moved\n"); + INF("move window message"); return 0; case WM_SIZING: - printf (" * ecore message : sizing\n"); + INF("sizing window message"); _ecore_win32_event_handle_resize(data); _ecore_win32_event_handle_configure_notify(data); return TRUE; case WM_SIZE: - printf (" * ecore message : sized\n"); + INF("size window message"); return 0; /* case WM_WINDOWPOSCHANGING: */ /* { */ @@ -362,26 +449,67 @@ _ecore_win32_window_procedure(HWND window, /* _ecore_win32_event_handle_configure_notify(data); */ /* return 0; */ case WM_WINDOWPOSCHANGED: - { - RECT rect; - GetClientRect(window, &rect); - printf (" *** ecore message : WINDOWPOSCHANGED %ld %ld\n", - rect.right - rect.left, rect.bottom - rect.top); - } + INF("position changed window message"); _ecore_win32_event_handle_configure_notify(data); + _ecore_win32_event_handle_expose(data); return 0; - case WM_ENTERSIZEMOVE : - printf (" * ecore message : WM_ENTERSIZEMOVE \n"); + case WM_ENTERSIZEMOVE: + INF("enter size move window message"); return 0; case WM_EXITSIZEMOVE: - printf (" * ecore message : WM_EXITSIZEMOVE\n"); + 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; - printf (" * ecore message : paint\n"); + INF("paint message"); + if (GetUpdateRect(window, &rect, FALSE)) { PAINTSTRUCT ps; @@ -391,22 +519,323 @@ _ecore_win32_window_procedure(HWND window, data->update = rect; _ecore_win32_event_handle_expose(data); EndPaint(window, &ps); - printf (" * %ld %ld %ld %ld\n", - rect.left, - rect.top, - rect.right - rect.left, - rect.bottom - rect.top); } return 0; } case WM_SETREDRAW: - printf (" * ecore message : WM_SETREDRAW\n"); + INF("set redraw message"); return 0; case WM_SYNCPAINT: - printf (" * ecore message : WM_SYNCPAINT\n"); + 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 index 7e89f9a..9b58c95 100644 --- a/src/lib/ecore_win32/ecore_win32_cursor.c +++ b/src/lib/ecore_win32/ecore_win32_cursor.c @@ -1,7 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif @@ -10,13 +6,160 @@ #include #undef WIN32_LEAN_AND_MEAN +#include + #include "Ecore_Win32.h" #include "ecore_win32_private.h" +/*============================================================================* + * Local * + *============================================================================*/ + + +/*============================================================================* + * Global * + *============================================================================*/ -/***** API *****/ -Ecore_Win32_Cursor * +/*============================================================================* + * 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, @@ -28,6 +171,11 @@ ecore_win32_cursor_new(const void *pixels_and, 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); @@ -45,18 +193,40 @@ ecore_win32_cursor_new(const void *pixels_and, return cursor; } -void +/** + * @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); } -Ecore_Win32_Cursor * -ecore_win32_cursor_shape_get(Ecore_Win32_Cursor_Shape shape) +/** + * @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: @@ -111,13 +281,25 @@ ecore_win32_cursor_shape_get(Ecore_Win32_Cursor_Shape shape) return cursor; } -int -ecore_win32_cursor_size_get(void) +/** + * @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) { - int width; - int height; + INF("geting size cursor"); - width = GetSystemMetrics(SM_CXCURSOR); - height = GetSystemMetrics(SM_CYCURSOR); - return (width > height) ? width : height; + 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 index 4b0b342..4476b2b 100644 --- a/src/lib/ecore_win32/ecore_win32_event.c +++ b/src/lib/ecore_win32/ecore_win32_event.c @@ -1,7 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif @@ -14,20 +10,34 @@ #undef WIN32_LEAN_AND_MEAN #include -#include "Ecore.h" +#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 double _ecore_win32_mouse_down_last_time = 0; -static double _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_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); @@ -35,15 +45,18 @@ static void _ecore_win32_event_free_key_down(void *data, static void _ecore_win32_event_free_key_up(void *data, void *ev); -static int _ecore_win32_event_keystroke_get(int key, - char **keyname, - char **keysymbol, - char **keycompose); +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); +static int _ecore_win32_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers); /***** Global functions definitions *****/ @@ -52,94 +65,94 @@ void _ecore_win32_event_handle_key_press(Ecore_Win32_Callback_Data *msg, int is_keystroke) { - Ecore_Win32_Event_Key_Down *e; + Ecore_Event_Key *e; - e = (Ecore_Win32_Event_Key_Down *)malloc(sizeof(Ecore_Win32_Event_Key_Down)); + 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(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) + if (!_ecore_win32_event_keystroke_get(msg, + EINA_TRUE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) { free(e); return; } - goto store_key; } else { if (!_ecore_win32_event_char_get(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) { free(e); return; } } - store_key: - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); if (!e->window) { free(e); return; } - e->time = (double)msg->time / 1000.0; + e->event_window = e->window; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; + _ecore_win32_event_last_time = e->timestamp; - ecore_event_add(ECORE_WIN32_EVENT_KEY_DOWN, e, _ecore_win32_event_free_key_down, NULL); + 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, - int is_keystroke) +_ecore_win32_event_handle_key_release(Ecore_Win32_Callback_Data *msg) { - Ecore_Win32_Event_Key_Up *e; + Ecore_Event_Key *e; + + INF("key released"); - e = (Ecore_Win32_Event_Key_Up *)calloc(1, sizeof(Ecore_Win32_Event_Key_Up)); + e = (Ecore_Event_Key *)calloc(1, sizeof(Ecore_Event_Key)); if (!e) return; - if (is_keystroke) - { - if (!_ecore_win32_event_keystroke_get(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) - { - free(e); - return; - } - goto store_key; - } - else + if (!_ecore_win32_event_keystroke_get(msg, + EINA_FALSE, + (char **)&e->keyname, + (char **)&e->key, + (char **)&e->string, + &e->modifiers)) { - if (!_ecore_win32_event_char_get(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) + 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; } } - store_key: - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); if (!e->window) { free(e); return; } - e->time = (double)msg->time / 1000.0; + e->event_window = e->window; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; + _ecore_win32_event_last_time = e->timestamp; - ecore_event_add(ECORE_WIN32_EVENT_KEY_UP, e, _ecore_win32_event_free_key_up, NULL); + ecore_event_add(ECORE_EVENT_KEY_UP, e, _ecore_win32_event_free_key_up, NULL); } void @@ -148,74 +161,79 @@ _ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg, { Ecore_Win32_Window *window; - window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + INF("mouse button pressed"); + + window = (Ecore_Win32_Window *)GetWindowLongPtr(msg->window, GWLP_USERDATA); if (button > 3) { - Ecore_Win32_Event_Mouse_Wheel *e; + Ecore_Event_Mouse_Wheel *e; - e = (Ecore_Win32_Event_Mouse_Wheel *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Wheel)); + e = (Ecore_Event_Mouse_Wheel *)calloc(1, sizeof(Ecore_Event_Mouse_Wheel)); if (!e) return; - e->window = window; - e->direction = 0; + 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->time = (double)msg->time / 1000.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->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_WHEEL, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_WHEEL, e, NULL, NULL); } else { { - Ecore_Win32_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_Win32_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = window; + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { - Ecore_Win32_Event_Mouse_Button_Down *e; + 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.0; - _ecore_win32_mouse_down_last_last_time = 0.0; + _ecore_win32_mouse_down_last_time = 0; + _ecore_win32_mouse_down_last_last_time = 0; } - e = (Ecore_Win32_Event_Mouse_Button_Down *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Button_Down)); + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); if (!e) return; - e->window = window; - e->button = button; + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - if (((e->time - _ecore_win32_mouse_down_last_time) <= _ecore_win32_double_click_time) && - (e->window == _ecore_win32_mouse_down_last_window)) + 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->time - _ecore_win32_mouse_down_last_last_time) <= (2.0 * _ecore_win32_double_click_time)) && - (e->window == _ecore_win32_mouse_down_last_window) && - (e->window == _ecore_win32_mouse_down_last_last_window)) + 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; @@ -226,116 +244,123 @@ _ecore_win32_event_handle_button_press(Ecore_Win32_Callback_Data *msg, if (!e->double_click && !e->triple_click) _ecore_win32_mouse_up_count = 0; - _ecore_win32_event_last_time = e->time; - _ecore_win32_event_last_window = e->window; + _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 = e->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->time; + _ecore_win32_mouse_down_last_time = e->timestamp; } - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); } } -/* printf (" * ecore event button press\n"); */ } void _ecore_win32_event_handle_button_release(Ecore_Win32_Callback_Data *msg, - int button) + int button) { Ecore_Win32_Window *window; - window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + INF("mouse button released"); + + window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); { - Ecore_Win32_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_Win32_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = window; + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { - Ecore_Win32_Event_Mouse_Button_Up *e; + Ecore_Event_Mouse_Button *e; - e = (Ecore_Win32_Event_Mouse_Button_Up *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Button_Up)); + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); if (!e) return; - e->window = window; - e->button = button; + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; _ecore_win32_mouse_up_count++; if ((_ecore_win32_mouse_up_count >= 2) && - ((e->time - _ecore_win32_mouse_down_last_time) <= _ecore_win32_double_click_time) && - (e->window == _ecore_win32_mouse_down_last_window)) + ((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->time - _ecore_win32_mouse_down_last_last_time) <= (2.0 * _ecore_win32_double_click_time)) && - (e->window == _ecore_win32_mouse_down_last_window) && - (e->window == _ecore_win32_mouse_down_last_last_window)) + ((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->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); } - -/* printf (" * ecore event button release\n"); */ } void _ecore_win32_event_handle_motion_notify(Ecore_Win32_Callback_Data *msg) { - Ecore_Win32_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; + + INF("mouse moved"); - e = (Ecore_Win32_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } void _ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg) { { - Ecore_Win32_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; + + INF("mouse in"); - e = (Ecore_Win32_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->event_window = e->window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { @@ -344,12 +369,12 @@ _ecore_win32_event_handle_enter_notify(Ecore_Win32_Callback_Data *msg) e = (Ecore_Win32_Event_Mouse_In *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_In)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp ; - _ecore_win32_event_last_time = e->time; + _ecore_win32_event_last_time = e->timestamp; ecore_event_add(ECORE_WIN32_EVENT_MOUSE_IN, e, NULL, NULL); } @@ -359,20 +384,23 @@ void _ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg) { { - Ecore_Win32_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_Win32_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Move)); + INF("mouse out"); + + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (Ecore_Window)GetWindowLongPtr(msg->window, GWLP_USERDATA); + e->event_window = e->window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; - _ecore_win32_event_last_window = e->window; + _ecore_win32_event_last_time = e->timestamp; + _ecore_win32_event_last_window = (Ecore_Win32_Window *)e->window; - ecore_event_add(ECORE_WIN32_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { @@ -381,12 +409,12 @@ _ecore_win32_event_handle_leave_notify(Ecore_Win32_Callback_Data *msg) e = (Ecore_Win32_Event_Mouse_Out *)calloc(1, sizeof(Ecore_Win32_Event_Mouse_Out)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->timestamp; - _ecore_win32_event_last_time = e->time; + _ecore_win32_event_last_time = e->timestamp; ecore_event_add(ECORE_WIN32_EVENT_MOUSE_OUT, e, NULL, NULL); } @@ -397,13 +425,15 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; - _ecore_win32_event_last_time = e->time; + 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); } @@ -413,13 +443,15 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; - _ecore_win32_event_last_time = e->time; + 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); } @@ -429,18 +461,19 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + 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; -/* printf (" * ecore : event expose %d %d\n", e->width, e->height); */ - e->time = _ecore_win32_event_last_time; + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_DAMAGE, e, NULL, NULL); } @@ -450,12 +483,14 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CREATE, e, NULL, NULL); } @@ -465,12 +500,14 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; + 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); @@ -481,12 +518,14 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_SHOW, e, NULL, NULL); } @@ -496,12 +535,14 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); - e->time = _ecore_win32_event_last_time; + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_HIDE, e, NULL, NULL); } @@ -513,6 +554,8 @@ _ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg) 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; @@ -524,14 +567,13 @@ _ecore_win32_event_handle_configure_notify(Ecore_Win32_Callback_Data *msg) return; } -/* printf ("_ecore_win32_event_handle_configure_notify\n"); */ - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); - e->abovewin = (void *)GetWindowLong(window_pos->hwndInsertAfter, GWL_USERDATA); + 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->time = _ecore_win32_event_last_time; + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_CONFIGURE, e, NULL, NULL); } @@ -542,17 +584,18 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); + e->window = (void *)GetWindowLongPtr(msg->window, GWLP_USERDATA); e->width = rect.right - rect.left; e->height = rect.bottom - rect.top; - e->time = _ecore_win32_event_last_time; -/* printf (" * _ecore_win32_event_handle_resize %d %d\n", e->width, e->height); */ + e->timestamp = _ecore_win32_event_last_time; ecore_event_add(ECORE_WIN32_EVENT_WINDOW_RESIZE, e, NULL, NULL); } @@ -562,11 +605,13 @@ _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 *)GetWindowLong(msg->window, GWL_USERDATA); - e->time = _ecore_win32_event_last_time; + 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); } @@ -575,40 +620,51 @@ _ecore_win32_event_handle_delete_request(Ecore_Win32_Callback_Data *msg) /***** Private functions definitions *****/ static void -_ecore_win32_event_free_key_down(void *data, +_ecore_win32_event_free_key_down(void *data __UNUSED__, void *ev) { - Ecore_Win32_Event_Key_Down *e; + Ecore_Event_Key *e; e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->keycompose) free(e->keycompose); + 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, +_ecore_win32_event_free_key_up(void *data __UNUSED__, void *ev) { - Ecore_Win32_Event_Key_Up *e; + Ecore_Event_Key *e; e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->keycompose) free(e->keycompose); + 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(int key, - char **keyname, - char **keysymbol, - char **keycompose) +_ecore_win32_event_keystroke_get(Ecore_Win32_Callback_Data *msg, + Eina_Bool is_down, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers) { - char *kn; - char *ks; - char *kc; + 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; @@ -618,55 +674,337 @@ _ecore_win32_event_keystroke_get(int key, { /* Keystroke */ case VK_PRIOR: - kn = "KP_Prior"; - ks = "KP_Prior"; - kc = ""; + if (is_extended) + { + kn = "Prior"; + ks = "Prior"; + kc = NULL; + } + else + { + kn = "KP_Prior"; + ks = "KP_9"; + kc = "KP_Prior"; + } break; case VK_NEXT: - kn = "KP_Next"; - ks = "KP_Next"; - kc = ""; + if (is_extended) + { + kn = "Next"; + ks = "Next"; + kc = NULL; + } + else + { + kn = "KP_Next"; + ks = "KP_3"; + kc = "KP_Next"; + } break; case VK_END: - kn = "KP_End"; - ks = "KP_End"; - kc = ""; + if (is_extended) + { + kn = "End"; + ks = "End"; + kc = NULL; + } + else + { + kn = "KP_End"; + ks = "KP_1"; + kc = "KP_End"; + } break; case VK_HOME: - kn = "KP_Home"; - ks = "KP_Home"; - kc = ""; + if (is_extended) + { + kn = "Home"; + ks = "Home"; + kc = NULL; + } + else + { + kn = "KP_Home"; + ks = "KP_7"; + kc = "KP_Home"; + } break; case VK_LEFT: - kn = "KP_Left"; - ks = "KP_Left"; - kc = ""; + if (is_extended) + { + kn = "Left"; + ks = "Left"; + kc = NULL; + } + else + { + kn = "KP_Left"; + ks = "KP_4"; + kc = "KP_Left"; + } break; case VK_UP: - kn = "KP_Up"; - ks = "KP_Up"; - kc = ""; + if (is_extended) + { + kn = "Up"; + ks = "Up"; + kc = NULL; + } + else + { + kn = "KP_Up"; + ks = "KP_8"; + kc = "KP_Up"; + } break; case VK_RIGHT: - kn = "KP_Right"; - ks = "KP_Right"; - kc = ""; + if (is_extended) + { + kn = "Right"; + ks = "Right"; + kc = NULL; + } + else + { + kn = "KP_Right"; + ks = "KP_6"; + kc = "KP_Right"; + } break; case VK_DOWN: - kn = "KP_Down"; - ks = "KP_Down"; - kc = ""; + if (is_extended) + { + kn = "Down"; + ks = "Down"; + kc = NULL; + } + else + { + kn = "KP_Down"; + ks = "KP_2"; + kc = "KP_Down"; + } break; case VK_INSERT: - kn = "KP_Insert"; - ks = "KP_Insert"; - kc = ""; + if (is_extended) + { + kn = "Insert"; + ks = "Insert"; + kc = NULL; + } + else + { + kn = "KP_Insert"; + ks = "KP_0"; + kc = "KP_Insert"; + } break; case VK_DELETE: - kn = "KP_Delete"; - ks = "KP_Delete"; - kc = ""; + 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"; @@ -788,9 +1126,53 @@ _ecore_win32_event_keystroke_get(int key, kc = ""; break; default: - /* other non keystroke characters */ - return 0; + { + /* 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); @@ -800,69 +1182,88 @@ _ecore_win32_event_keystroke_get(int key, *keyname = NULL; return 0; } - *keycompose = strdup(kc); - if (!*keycompose) + if (!kc) + *keycompose = NULL; + else { - free(*keyname); - free(*keysymbol); - *keyname = NULL; - *keysymbol = NULL; - return 0; + *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) +_ecore_win32_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose, + unsigned int *modifiers) { - char kn[32]; - char ks[32]; - char *kc; + 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: - strncpy(kn, "Backspace", 32); - strncpy(ks, "Backspace", 32); - kc = ""; + kn = "BackSpace"; + ks = "BackSpace"; + kc = "\b"; break; case VK_TAB: - strncpy(kn, "Tab", 32); - strncpy(ks, "Tab", 32); - kc = ""; + kn = "Tab"; + ks = "Tab"; + kc = "\t"; break; case 0x0a: /* Line feed (Shift + Enter) */ - strncpy(kn, "LineFeed", 32); - strncpy(ks, "LineFeed", 32); - kc = ""; + kn = "LineFeed"; + ks = "LineFeed"; + kc = "LineFeed"; break; case VK_RETURN: - strncpy(kn, "Return", 32); - strncpy(ks, "Return", 32); - kc = ""; + kn = "Return"; + ks = "Return"; + kc = "\n"; break; case VK_ESCAPE: - strncpy(kn, "Escape", 32); - strncpy(ks, "Escape", 32); - kc = ""; + kn = "Escape"; + ks = "Escape"; + kc = "\e"; + break; + case VK_SPACE: + kn = "space"; + ks = "space"; + kc = " "; break; default: /* displayable characters */ - printf (" * key : %d\n", key); - kn[0] = (TCHAR)key; - kn[1] = '\0'; - ks[0] = (TCHAR)key; - ks[1] = '\0'; - kc = ""; + buf[0] = key; + buf[1] = '\0'; + kn = buf; + ks = buf; + kc = buf; break; } *keyname = strdup(kn); @@ -884,5 +1285,23 @@ _ecore_win32_event_char_get(int key, 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 index 93b6fa7..e3e4426 100644 --- a/src/lib/ecore_win32/ecore_win32_private.h +++ b/src/lib/ecore_win32/ecore_win32_private.h @@ -1,26 +1,63 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef __ECORE_WIN32_PRIVATE_H__ #define __ECORE_WIN32_PRIVATE_H__ -#define ECORE_WIN32_WINDOW_CLASS "Ecore_Win32_Window_Class" +#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; - long time; - int x; - int y; + 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 @@ -34,8 +71,8 @@ struct _Ecore_Win32_Window unsigned int min_height; unsigned int max_width; unsigned int max_height; - unsigned int base_width; - unsigned int base_height; + int base_width; + int base_height; unsigned int step_width; unsigned int step_height; @@ -68,19 +105,38 @@ struct _Ecore_Win32_Window 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 double _ecore_win32_event_last_time; +extern unsigned long _ecore_win32_event_last_time; extern Ecore_Win32_Window *_ecore_win32_event_last_window; -char *_ecore_win32_hwnd_str_get(HWND 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, 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); @@ -97,5 +153,18 @@ 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 index a3129ee..36f8a86 100644 --- a/src/lib/ecore_win32/ecore_win32_window.c +++ b/src/lib/ecore_win32/ecore_win32_window.c @@ -1,7 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifdef HAVE_CONFIG_H # include #endif @@ -13,11 +9,18 @@ #include #undef WIN32_LEAN_AND_MEAN +#include + #include "Ecore_Win32.h" #include "ecore_win32_private.h" +/*============================================================================* + * Local * + *============================================================================*/ -/***** Private declarations *****/ +/** + * @cond LOCAL + */ typedef enum _Ecore_Win32_Window_Z_Order Ecore_Win32_Window_Z_Order; @@ -29,59 +32,232 @@ enum _Ecore_Win32_Window_Z_Order 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); +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; + } -/***** API *****/ + 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; + } -Ecore_Win32_Window * + 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); } -/* simulate X11 override windows */ -Ecore_Win32_Window * +/** + * @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_POPUP & ~(WS_CAPTION | WS_THICKFRAME)); } -void -ecore_win32_window_del(Ecore_Win32_Window *window) +/** + * @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; - DestroyWindow(((struct _Ecore_Win32_Window *)window)->window); + INF("destroying window"); + + if (window->shape.mask) + free(window->shape.mask); + + DestroyWindow(window->window); free(window); - printf ("ecore_win32_window_del\n"); } -void * +/** + * @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 ((struct _Ecore_Win32_Window *)window)->window; + return window->window; } /* @@ -112,118 +288,193 @@ ecore_win32_window_configure(Ecore_Win32_Window *window, default: return; } - SetWindowPos((struct _Ecore_Win32_Window *)window->window, w, x, y, width, height, ???); + SetWindowPos((Ecore_Win32_Window *)window->window, w, x, y, width, height, ???); } */ -void +/** + * @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; - HWND w; + /* FIXME: on fullscreen, should not move it */ if (!window) return; - printf ("ecore_win32_window_move %p : %d %d\n", window, x, y); - w = ((struct _Ecore_Win32_Window *)window)->window; - if (!GetWindowRect(w, &rect)) - return; + INF("moving window (%dx%d)", x, y); + + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } - MoveWindow(w, x, y, - rect.right - rect.left, - rect.bottom - rect.top, - TRUE); + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } } -void +/** + * @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; - struct _Ecore_Win32_Window *w; - DWORD style; - int x; - int y; - + RECT rect; + DWORD style; + int x; + int y; + int minimal_width; + int minimal_height; + + /* FIXME: on fullscreen, should not resize it */ if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - if (!GetWindowRect(w->window, &rect)) 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); - printf ("ecore_win32_window_resize 0 : %p (%d %d) (%d %d) (%d %d)\n", - w, - w->min_width, - w->min_height, - w->max_width, - w->max_height, - width, - height); + if (!GetWindowRect(window->window, &rect)) + { + ERR("GetWindowRect() failed"); + return; + } x = rect.left; y = rect.top; rect.left = 0; rect.top = 0; -/* if (width < w->min_width) width = w->min_width; */ -/* if (width > w->max_width) width = w->max_width; */ -/* printf ("ecore_win32_window_resize 1 : %d %d %d\n", w->min_height, w->max_height, height); */ -/* if (height < w->min_height) height = w->min_height; */ -/* printf ("ecore_win32_window_resize 2 : %d %d\n", w->max_height, height); */ -/* if (height > w->max_height) height = w->max_height; */ -/* printf ("ecore_win32_window_resize 3 : %d %d\n", w->max_height, height); */ + 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; - style = GetWindowLong(w->window, GWL_STYLE); + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } if (!AdjustWindowRect(&rect, style, FALSE)) - return; + { + ERR("AdjustWindowRect() failed"); + return; + } - if (!MoveWindow(w->window, x, y, + if (!MoveWindow(window->window, x, y, rect.right - rect.left, rect.bottom - rect.top, - FALSE)) + TRUE)) { - printf (" MEEERDE !!!\n"); + ERR("MoveWindow() failed"); } - printf ("ecore_win32_window_resize 4 : %d %d\n", width, height); } -void +/** + * @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; - struct _Ecore_Win32_Window *w; - DWORD style; + RECT rect; + DWORD style; + int minimal_width; + int minimal_height; + /* FIXME: on fullscreen, should not move/resize it */ if (!window) return; - printf ("ecore_win32_window_move_resize 0 : %p %d %d\n", window, width, height); - w = ((struct _Ecore_Win32_Window *)window); + 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 ((unsigned int)width < w->min_width) width = w->min_width; - if ((unsigned int)width > w->max_width) width = w->max_width; - if ((unsigned int)height < w->min_height) height = w->min_height; - if ((unsigned int)height > w->max_height) height = w->max_height; - printf ("ecore_win32_window_move_resize 1 : %d %d\n", width, height); + 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; - style = GetWindowLong(w->window, GWL_STYLE); - if (!AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW | WS_SIZEBOX, FALSE)) - return; + if (!(style = GetWindowLong(window->window, GWL_STYLE))) + { + ERR("GetWindowLong() failed"); + return; + } + if (!AdjustWindowRect(&rect, style, FALSE)) + { + ERR("AdjustWindowRect() failed"); + return; + } - MoveWindow(w->window, x, y, - rect.right - rect.left, - rect.bottom - rect.top, - TRUE); + if (!MoveWindow(window->window, x, y, + rect.right - rect.left, + rect.bottom - rect.top, + TRUE)) + { + ERR("MoveWindow() failed"); + } } -void +/** + * @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, @@ -234,7 +485,8 @@ ecore_win32_window_geometry_get(Ecore_Win32_Window *window, int w; int h; - printf ("ecore_win32_window_geometry_get %p\n", window); + INF("getting window geometry"); + if (!window) { if (x) *x = 0; @@ -245,9 +497,10 @@ ecore_win32_window_geometry_get(Ecore_Win32_Window *window, return; } - if (!GetClientRect(((struct _Ecore_Win32_Window *)window)->window, - &rect)) + if (!GetClientRect(window->window, &rect)) { + ERR("GetClientRect() failed"); + if (x) *x = 0; if (y) *y = 0; if (width) *width = 0; @@ -259,9 +512,10 @@ ecore_win32_window_geometry_get(Ecore_Win32_Window *window, w = rect.right - rect.left; h = rect.bottom - rect.top; - if (!GetWindowRect(((struct _Ecore_Win32_Window *)window)->window, - &rect)) + if (!GetWindowRect(window->window, &rect)) { + ERR("GetWindowRect() failed"); + if (x) *x = 0; if (y) *y = 0; if (width) *width = 0; @@ -276,14 +530,29 @@ ecore_win32_window_geometry_get(Ecore_Win32_Window *window, if (height) *height = h; } -void +/** + * @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; - printf ("ecore_win32_window_size_get %p\n", window); + INF("getting window size"); + if (!window) { if (width) *width = GetSystemMetrics(SM_CXSCREEN); @@ -292,9 +561,10 @@ ecore_win32_window_size_get(Ecore_Win32_Window *window, return; } - if (!GetClientRect(((struct _Ecore_Win32_Window *)window)->window, - &rect)) + if (!GetClientRect(window->window, &rect)) { + ERR("GetClientRect() failed"); + if (width) *width = 0; if (height) *height = 0; } @@ -303,171 +573,288 @@ ecore_win32_window_size_get(Ecore_Win32_Window *window, if (height) *height = rect.bottom - rect.top; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; printf ("ecore_win32_window_size_min_set : %p %d %d\n", window, min_width, min_height); - w = (struct _Ecore_Win32_Window *)window; - w->min_width = min_width; - w->min_height = min_height; + window->min_width = min_width; + window->min_height = min_height; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - printf ("ecore_win32_window_size_min_get : %p %d %d\n", window, w->min_width, w->min_height); - if (min_width) *min_width = w->min_width; - if (min_height) *min_height = w->min_height; + 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; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; printf ("ecore_win32_window_size_max_set : %p %d %d\n", window, max_width, max_height); - w = (struct _Ecore_Win32_Window *)window; - w->max_width = max_width; - w->max_height = max_height; + window->max_width = max_width; + window->max_height = max_height; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - printf ("ecore_win32_window_size_max_get : %p %d %d\n", window, w->max_width, w->max_height); - if (max_width) *max_width = w->max_width; - if (max_height) *max_height = w->max_height; + 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; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - printf ("ecore_win32_window_size_base_set : %p %d %d\n", window, base_width, base_height); if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - w->base_width = base_width; - w->base_height = base_height; + window->base_width = base_width; + window->base_height = base_height; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - printf ("ecore_win32_window_size_base_get : %p %d %d\n", window, w->base_width, w->base_height); - if (base_width) *base_width = w->base_width; - if (base_height) *base_height = w->base_height; + 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; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - printf ("ecore_win32_window_size_step_set : %p %d %d\n", window, step_width, step_height); if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - w->step_width = step_width; - w->step_height = step_height; + window->step_width = step_width; + window->step_height = step_height; } -void +/** + * @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) { - struct _Ecore_Win32_Window *w; - if (!window) return; - w = (struct _Ecore_Win32_Window *)window; - printf ("ecore_win32_window_size_step_get : %p %d %d\n", window, w->step_width, w->step_height); - if (step_width) *step_width = w->step_width; - if (step_height) *step_height = w->step_height; + 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; } -/* TODO: ecore_win32_window_shaped_set */ - -void +/** + * @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; - printf (" ** ecore_win32_window_show %p\n", window); - ShowWindow(((struct _Ecore_Win32_Window *)window)->window, SW_SHOWNORMAL); - UpdateWindow(((struct _Ecore_Win32_Window *)window)->window); + INF("showing window"); + + ShowWindow(window->window, SW_SHOWNORMAL); + if (!UpdateWindow(window->window)) + { + ERR("UpdateWindow() failed"); + } } /* FIXME: seems to block the taskbar */ -void +/** + * @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; - printf (" ** ecore_win32_window_hide %p\n", window); - ShowWindow(((struct _Ecore_Win32_Window *)window)->window, SW_HIDE); + INF("hiding window"); + + ShowWindow(window->window, SW_HIDE); } -void +/** + * @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; - printf (" ** ecore_win32_window_raise %p\n", window); - SetWindowPos(((struct _Ecore_Win32_Window *)window)->window, - HWND_TOP, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + INF("raising window"); + + if (!SetWindowPos(window->window, + HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + { + ERR("SetWindowPos() failed"); + } } -void +/** + * @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; - printf (" ** ecore_win32_window_lower %p\n", window); - SetWindowPos(((struct _Ecore_Win32_Window *)window)->window, - HWND_BOTTOM, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); + INF("lowering window"); + + if (!SetWindowPos(window->window, + HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) + { + ERR("SetWindowPos() failed"); + } } -void +/** + * @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) { @@ -475,184 +862,354 @@ ecore_win32_window_title_set(Ecore_Win32_Window *window, if (!title || !title[0]) return; - SetWindowText(((struct _Ecore_Win32_Window *)window)->window, title); + INF("setting window title"); + + if (!SetWindowText(window->window, title)) + { + ERR("SetWindowText() failed"); + } } -void -ecore_win32_window_focus_set(Ecore_Win32_Window *window) +/** + * @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; - SetFocus(((struct _Ecore_Win32_Window *)window)->window); + INF("focusing window"); + + if (!SetFocus(window->window)) + { + ERR("SetFocus() failed"); + } } -void -ecore_win32_window_iconified_set(Ecore_Win32_Window *window, - int on) +/** + * @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) { - struct _Ecore_Win32_Window *ew; + 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; - ew = (struct _Ecore_Win32_Window *)window; - if (((ew->iconified) && (on)) || - ((!ew->iconified) && (!on))) + if (((window->iconified) && (on)) || + ((!window->iconified) && (!on))) return; - if (on) - { - ShowWindow(ew->window, - SW_MINIMIZE); - } - else - { - ShowWindow(ew->window, - SW_RESTORE); - } - ew->iconified = on; + INF("iconifying window: %s", on ? "yes" : "no"); + + ShowWindow(window->window, on ? SW_MINIMIZE : SW_RESTORE); + window->iconified = on; } -void +/** + * @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, - int on) + Eina_Bool on) { - RECT rect; - DWORD style; - struct _Ecore_Win32_Window *ew; - HWND w; + RECT rect; + DWORD style; if (!window) return; - printf (" ** ecore_win32_window_borderless_set %p %d\n", window, on); - ew = (struct _Ecore_Win32_Window *)window; - if (((ew->borderless) && (on)) || - ((!ew->borderless) && (!on))) + if (((window->borderless) && (on)) || + ((!window->borderless) && (!on))) return; - w = ew->window; + INF("setting window without border: %s", on ? "yes" : "no"); - style = GetWindowLong(w, GWL_STYLE); + style = GetWindowLong(window->window, GWL_STYLE); if (on) { - if (!GetClientRect(w, &rect)) return; - SetWindowLong(w, GWL_STYLE, style & ~WS_CAPTION); + 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(w, &rect)) return; - style |= WS_CAPTION; - AdjustWindowRect (&rect, style, FALSE); - SetWindowLong(w, GWL_STYLE, style); + 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; + } } - SetWindowPos(w, HWND_TOPMOST, - rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_NOMOVE | SWP_FRAMECHANGED); - ew->borderless = on; + 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; } -void +/** + * @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, - int on) + Eina_Bool on) { - struct _Ecore_Win32_Window *ew; - HWND w; - int width; - int height; - if (!window) return; - ew = (struct _Ecore_Win32_Window *)window; - if (((ew->fullscreen) && (on)) || - ((!ew->fullscreen) && (!on))) + if (((window->fullscreen) && (on)) || + ((!window->fullscreen) && (!on))) return; - ew->fullscreen = on; - w = ew->window; + INF("setting fullscreen: %s", on ? "yes" : "no"); + + window->fullscreen = !!on; if (on) { - if (!GetWindowRect(w, &ew->rect)) return; - ew->style = GetWindowLong(w, GWL_STYLE); - width = GetSystemMetrics (SM_CXSCREEN); - height = GetSystemMetrics (SM_CYSCREEN); - if (!SetWindowLong(w, GWL_STYLE, - (ew->style & ~WS_OVERLAPPEDWINDOW) | WS_POPUP)) - return; - SetWindowPos(w, HWND_TOP, 0, 0, width, height, - SWP_NOCOPYBITS | SWP_SHOWWINDOW); + 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 { - if (!SetWindowLong(w, GWL_STYLE, ew->style)) - return; - SetWindowPos(w, HWND_NOTOPMOST, - ew->rect.left, - ew->rect.top, - ew->rect.right - ew->rect.left, - ew->rect.bottom - ew->rect.top, - SWP_NOCOPYBITS | SWP_SHOWWINDOW); + 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; + } } } -void +/** + * @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) { - SetClassLong(((struct _Ecore_Win32_Window *)window)->window, - GCL_HCURSOR, (LONG)cursor); + INF("setting cursor"); + + if (!window || !cursor) + return; + + if (!SetClassLongPtr(window->window, + GCLP_HCURSOR, (LONG_PTR)cursor)) + { + ERR("SetClassLong() failed"); + } } -void +/** + * @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 (!num) + 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: - ((struct _Ecore_Win32_Window *)window)->state.iconified = 1; + window->state.iconified = 1; break; case ECORE_WIN32_WINDOW_STATE_MODAL: - ((struct _Ecore_Win32_Window *)window)->state.modal = 1; + window->state.modal = 1; break; case ECORE_WIN32_WINDOW_STATE_STICKY: - ((struct _Ecore_Win32_Window *)window)->state.sticky = 1; + window->state.sticky = 1; break; case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT: - ((struct _Ecore_Win32_Window *)window)->state.maximized_vert = 1; + window->state.maximized_vert = 1; break; case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ: - ((struct _Ecore_Win32_Window *)window)->state.maximized_horz = 1; + window->state.maximized_horz = 1; break; case ECORE_WIN32_WINDOW_STATE_MAXIMIZED: - ((struct _Ecore_Win32_Window *)window)->state.maximized_horz = 1; - ((struct _Ecore_Win32_Window *)window)->state.maximized_vert = 1; + window->state.maximized_horz = 1; + window->state.maximized_vert = 1; break; case ECORE_WIN32_WINDOW_STATE_SHADED: - ((struct _Ecore_Win32_Window *)window)->state.shaded = 1; + window->state.shaded = 1; break; case ECORE_WIN32_WINDOW_STATE_HIDDEN: - ((struct _Ecore_Win32_Window *)window)->state.hidden = 1; + window->state.hidden = 1; break; case ECORE_WIN32_WINDOW_STATE_FULLSCREEN: - ((struct _Ecore_Win32_Window *)window)->state.fullscreen = 1; + window->state.fullscreen = 1; break; case ECORE_WIN32_WINDOW_STATE_ABOVE: - ((struct _Ecore_Win32_Window *)window)->state.above = 1; + window->state.above = 1; break; case ECORE_WIN32_WINDOW_STATE_BELOW: - ((struct _Ecore_Win32_Window *)window)->state.below = 1; + window->state.below = 1; break; case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION: - ((struct _Ecore_Win32_Window *)window)->state.demands_attention = 1; + window->state.demands_attention = 1; break; case ECORE_WIN32_WINDOW_STATE_UNKNOWN: /* nothing to be done */ @@ -661,262 +1218,201 @@ ecore_win32_window_state_set(Ecore_Win32_Window *window, } } -void +/** + * @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; + if (!window) return; + + INF("sending cursor state"); switch (state) { - case ECORE_WIN32_WINDOW_STATE_ICONIFIED: - if (((struct _Ecore_Win32_Window *)window)->state.iconified) - ecore_win32_window_iconified_set(window, set); - break; - case ECORE_WIN32_WINDOW_STATE_MODAL: - ((struct _Ecore_Win32_Window *)window)->state.modal = 1; - break; - case ECORE_WIN32_WINDOW_STATE_STICKY: - ((struct _Ecore_Win32_Window *)window)->state.sticky = 1; - break; - case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_VERT: - if (((struct _Ecore_Win32_Window *)window)->state.maximized_vert) - { - RECT rect; - int y; - int height; - - if (!SystemParametersInfo(SPI_GETWORKAREA, 0, - &rect, 0)) - break; - y = rect.top; - height = rect.bottom - rect.top; - - if (!GetClientRect(((struct _Ecore_Win32_Window *)window)->window, - &rect)) - break; - - MoveWindow(window, rect.left, y, - rect.right - rect.left, - height, - TRUE); - } - break; - case ECORE_WIN32_WINDOW_STATE_MAXIMIZED_HORZ: - if (((struct _Ecore_Win32_Window *)window)->state.maximized_horz) - { - RECT rect; - - if (!GetClientRect(((struct _Ecore_Win32_Window *)window)->window, - &rect)) - break; - - MoveWindow(window, 0, rect.top, - GetSystemMetrics(SM_CXSCREEN), - rect.bottom - rect.top, - TRUE); - } - break; - case ECORE_WIN32_WINDOW_STATE_MAXIMIZED: - if (((struct _Ecore_Win32_Window *)window)->state.maximized_vert && - ((struct _Ecore_Win32_Window *)window)->state.maximized_horz) - { - RECT rect; - - if (!SystemParametersInfo(SPI_GETWORKAREA, 0, - &rect, 0)) - break; - - MoveWindow(window, 0, 0, - GetSystemMetrics(SM_CXSCREEN), - rect.bottom - rect.top, - TRUE); - } - break; - case ECORE_WIN32_WINDOW_STATE_SHADED: - ((struct _Ecore_Win32_Window *)window)->state.shaded = 1; - break; - case ECORE_WIN32_WINDOW_STATE_HIDDEN: - ((struct _Ecore_Win32_Window *)window)->state.hidden = 1; - break; - case ECORE_WIN32_WINDOW_STATE_FULLSCREEN: - if (((struct _Ecore_Win32_Window *)window)->state.fullscreen) - ecore_win32_window_fullscreen_set(window, set); - break; - case ECORE_WIN32_WINDOW_STATE_ABOVE: - if (((struct _Ecore_Win32_Window *)window)->state.above) - SetWindowPos(((struct _Ecore_Win32_Window *)window)->window, - HWND_TOP, - 0, 0, - 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - break; - case ECORE_WIN32_WINDOW_STATE_BELOW: - if (((struct _Ecore_Win32_Window *)window)->state.below) - SetWindowPos(((struct _Ecore_Win32_Window *)window)->window, - HWND_BOTTOM, - 0, 0, - 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - break; - case ECORE_WIN32_WINDOW_STATE_DEMANDS_ATTENTION: - ((struct _Ecore_Win32_Window *)window)->state.demands_attention = 1; - break; - case ECORE_WIN32_WINDOW_STATE_UNKNOWN: - /* nothing to be done */ - break; + 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; } } -void +/** + * @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: - ((struct _Ecore_Win32_Window *)window)->type.desktop = 1; + window->type.desktop = 1; break; case ECORE_WIN32_WINDOW_TYPE_DOCK: - ((struct _Ecore_Win32_Window *)window)->type.dock = 1; + window->type.dock = 1; break; case ECORE_WIN32_WINDOW_TYPE_TOOLBAR: - ((struct _Ecore_Win32_Window *)window)->type.toolbar = 1; + window->type.toolbar = 1; break; case ECORE_WIN32_WINDOW_TYPE_MENU: - ((struct _Ecore_Win32_Window *)window)->type.menu = 1; + window->type.menu = 1; break; case ECORE_WIN32_WINDOW_TYPE_UTILITY: - ((struct _Ecore_Win32_Window *)window)->type.utility = 1; + window->type.utility = 1; break; case ECORE_WIN32_WINDOW_TYPE_SPLASH: - ((struct _Ecore_Win32_Window *)window)->type.splash = 1; + window->type.splash = 1; break; case ECORE_WIN32_WINDOW_TYPE_DIALOG: - ((struct _Ecore_Win32_Window *)window)->type.dialog = 1; + window->type.dialog = 1; break; case ECORE_WIN32_WINDOW_TYPE_NORMAL: - ((struct _Ecore_Win32_Window *)window)->type.normal = 1; + window->type.normal = 1; break; case ECORE_WIN32_WINDOW_TYPE_UNKNOWN: - ((struct _Ecore_Win32_Window *)window)->type.normal = 1; + window->type.normal = 1; break; } } - -/***** Private functions definitions *****/ - -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; - struct _Ecore_Win32_Window *w; - int minimal_width; - int minimal_height; - - w = (struct _Ecore_Win32_Window *)calloc(1, sizeof(struct _Ecore_Win32_Window)); - if (!w) - return NULL; - - printf (" *** ecore_win32_window_new : %p %d %d %d\n", - w, - width, height, GetSystemMetrics(SM_CXMIN)); - rect.left = 0; - rect.top = 0; - rect.right = width; - rect.bottom = height; - if (!AdjustWindowRect(&rect, style, FALSE)) - { - free(w); - return NULL; - } - printf (" * ecore : new debut : %ld %d %d\n", - rect.right - rect.left, GetSystemMetrics(SM_CXMIN), GetSystemMetrics(SM_CYMIN)); - - 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 = CreateWindow(ECORE_WIN32_WINDOW_CLASS, "", - style, - x, y, - rect.right - rect.left, - rect.bottom - rect.top, - parent ? ((struct _Ecore_Win32_Window *)parent)->window : NULL, - NULL, _ecore_win32_instance, NULL); - if (!w->window) - { - free(w); - return NULL; - } - - SetLastError(0); - if (!SetWindowLong(w->window, GWL_USERDATA, (LONG)w) && (GetLastError() != 0)) - { - 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; - - printf (" *** ecore_win32_window_new fin : (%d %d) (%d %d)\n", - w->min_width, - w->min_height, - w->max_width, - w->max_height); - - return w; -} +/** + * @} + */ diff --git a/src/lib/ecore_wince/Ecore_WinCE.h b/src/lib/ecore_wince/Ecore_WinCE.h index 0b6b46a..20c1975 100644 --- a/src/lib/ecore_wince/Ecore_WinCE.h +++ b/src/lib/ecore_wince/Ecore_WinCE.h @@ -1,16 +1,23 @@ +#ifndef __ECORE_WINCE_H__ +#define __ECORE_WINCE_H__ + /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + * DO NOT USE THIS HEADER. IT IS WORK IN PROGRESS. IT IS NOT FINAL AND + * THE API MAY CHANGE. */ -#ifndef __ECORE_WINCE_H__ -#define __ECORE_WINCE_H__ +#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 _WINCE +#ifdef _WIN32 # ifdef EFL_ECORE_WINCE_BUILD # ifdef DLL_EXPORT # define EAPI __declspec(dllexport) @@ -36,168 +43,209 @@ extern "C" { #endif +/** + * @defgroup Ecore_WinCE_Group Ecore_WinCE library + * + * @{ + */ -typedef void Ecore_WinCE_Window; +/** + * @typedef Ecore_WinCE_Window + * Abstract type for a window. + */ +typedef struct _Ecore_WinCE_Window Ecore_WinCE_Window; -/* Events */ -typedef struct _Ecore_WinCE_Event_Key_Down Ecore_WinCE_Event_Key_Down; -typedef struct _Ecore_WinCE_Event_Key_Up Ecore_WinCE_Event_Key_Up; -typedef struct _Ecore_WinCE_Event_Mouse_Button_Down Ecore_WinCE_Event_Mouse_Button_Down; -typedef struct _Ecore_WinCE_Event_Mouse_Button_Up Ecore_WinCE_Event_Mouse_Button_Up; -typedef struct _Ecore_WinCE_Event_Mouse_Move Ecore_WinCE_Event_Mouse_Move; +/** + * @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 struct _Ecore_WinCE_Event_Window_Destroy Ecore_WinCE_Event_Window_Destroy; -typedef struct _Ecore_WinCE_Event_Window_Hide Ecore_WinCE_Event_Window_Hide; -typedef struct _Ecore_WinCE_Event_Window_Show Ecore_WinCE_Event_Window_Show; -typedef struct _Ecore_WinCE_Event_Window_Delete_Request Ecore_WinCE_Event_Window_Delete_Request; -struct _Ecore_WinCE_Event_Key_Down -{ - Ecore_WinCE_Window *window; - char *keyname; - char *keysymbol; - char *keycompose; - double time; -}; +/** + * @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; -struct _Ecore_WinCE_Event_Key_Up -{ - Ecore_WinCE_Window *window; - char *keyname; - char *keysymbol; - char *keycompose; - double time; -}; +/** + * @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; -struct _Ecore_WinCE_Event_Mouse_Button_Down -{ - Ecore_WinCE_Window *window; - int button; - int x; - int y; - double time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; +/** + * @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; -struct _Ecore_WinCE_Event_Mouse_Button_Up -{ - Ecore_WinCE_Window *window; - int button; - int x; - int y; - double time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; +/** + * @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_Move -{ - Ecore_WinCE_Window *window; - int x; - int y; - double time; -}; +/** + * @struct _Ecore_WinCE_Event_Mouse_In + * Event sent when the mouse enters the window. + */ struct _Ecore_WinCE_Event_Mouse_In { - Ecore_WinCE_Window *window; - int x; - int y; - double time; + 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; - int x; - int y; - double time; + 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; - double time; + 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; - double time; + 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; - int x; - int y; - int width; - int height; - double time; + 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; - double time; + 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; - double time; + 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; - double time; + 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; - double time; + 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; - double time; + Ecore_WinCE_Window *window; /**< The window that received the event */ + long time; /**< The time the event occurred */ }; -EAPI extern int ECORE_WINCE_EVENT_KEY_DOWN; -EAPI extern int ECORE_WINCE_EVENT_KEY_UP; -EAPI extern int ECORE_WINCE_EVENT_MOUSE_BUTTON_DOWN; -EAPI extern int ECORE_WINCE_EVENT_MOUSE_BUTTON_UP; -EAPI extern int ECORE_WINCE_EVENT_MOUSE_MOVE; -EAPI extern int ECORE_WINCE_EVENT_MOUSE_IN; -EAPI extern int ECORE_WINCE_EVENT_MOUSE_OUT; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_IN; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_FOCUS_OUT; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_DAMAGE; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_CREATE; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_DESTROY; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_HIDE; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_SHOW; -EAPI extern int ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST; +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 double ecore_wince_current_time_get(void); -EAPI void ecore_wince_message_loop_begin (void); +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 */ @@ -207,17 +255,40 @@ EAPI Ecore_WinCE_Window *ecore_wince_window_new(Ecore_WinCE_Window *parent, int width, int height); -EAPI void ecore_wince_window_del(Ecore_WinCE_Window *window); +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_set(Ecore_WinCE_Window *window, int (*suspend)(int)); +EAPI void ecore_wince_window_suspend_cb_set(Ecore_WinCE_Window *window, int (*suspend_cb)(int)); -EAPI void ecore_wince_window_resume_set(Ecore_WinCE_Window *window, int (*resume)(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, @@ -229,8 +300,12 @@ EAPI void ecore_wince_window_size_get(Ecore_WinCE_Window *window, int *width, int *height); -EAPI void *ecore_wince_window_window_get(Ecore_WinCE_Window *window); +EAPI void ecore_wince_window_fullscreen_set(Ecore_WinCE_Window *window, + Eina_Bool on); +/** + * @} + */ #ifdef __cplusplus } diff --git a/src/lib/ecore_wince/Makefile.am b/src/lib/ecore_wince/Makefile.am index d5f3499..a264ffb 100644 --- a/src/lib/ecore_wince/Makefile.am +++ b/src/lib/ecore_wince/Makefile.am @@ -2,17 +2,20 @@ MAINTAINERCLEANFILES = Makefile.in AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_builddir)/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@ - -if BUILD_ECORE_WINCE - lib_LTLIBRARIES = libecore_wince.la -include_HEADERS = \ -Ecore_WinCE.h +includes_HEADERS = Ecore_WinCE.h +includesdir = $(includedir)/ecore-@VMAJ@ libecore_wince_la_SOURCES = \ ecore_wince.c \ @@ -21,11 +24,12 @@ ecore_wince_window.c libecore_wince_la_LIBADD = \ @WIN32_LIBS@ \ -$(top_builddir)/src/lib/ecore/libecore.la - -libecore_wince_la_LDFLAGS = @lt_no_undefined@ @lt_enable_auto_import@ -version-info @version_info@ +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +$(top_builddir)/src/lib/ecore/libecore.la \ +@EVAS_LIBS@ \ +@EINA_LIBS@ \ +@EVIL_LIBS@ -endif +libecore_wince_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ -EXTRA_DIST = \ -ecore_wince_private.h +EXTRA_DIST = ecore_wince_private.h diff --git a/src/lib/ecore_wince/ecore_wince.c b/src/lib/ecore_wince/ecore_wince.c index 71ebf77..5638ad3 100644 --- a/src/lib/ecore_wince/ecore_wince.c +++ b/src/lib/ecore_wince/ecore_wince.c @@ -1,6 +1,6 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif #include #include /* for printf */ @@ -9,163 +9,22 @@ #include #undef WIN32_LEAN_AND_MEAN -#include "Ecore.h" +#include +#include +#include + #include "Ecore_WinCE.h" #include "ecore_wince_private.h" - -/***** Global declarations *****/ - -double _ecore_wince_double_click_time = 0.25; -double _ecore_wince_event_last_time = 0.0; -Ecore_WinCE_Window *_ecore_wince_event_last_window = NULL; -HINSTANCE _ecore_wince_instance = NULL; - -int ECORE_WINCE_EVENT_KEY_DOWN = 0; -int ECORE_WINCE_EVENT_KEY_UP = 0; -int ECORE_WINCE_EVENT_MOUSE_BUTTON_DOWN = 0; -int ECORE_WINCE_EVENT_MOUSE_BUTTON_UP = 0; -int ECORE_WINCE_EVENT_MOUSE_MOVE = 0; -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; - - -/***** Private declarations *****/ - -static int _ecore_wince_init_count = 0; - - -LRESULT CALLBACK _ecore_wince_window_procedure(HWND window, - UINT message, - WPARAM window_param, - LPARAM data_param); - - -/***** API *****/ - -int -ecore_wince_init() -{ - WNDCLASS wc; - - if (_ecore_wince_init_count > 0) - { - _ecore_wince_init_count++; - return _ecore_wince_init_count; - } - - _ecore_wince_instance = GetModuleHandle(NULL); - if (!_ecore_wince_instance) - return 0; - - 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)) - { - FreeLibrary(_ecore_wince_instance); - return 0; - } - - if (!ECORE_WINCE_EVENT_KEY_DOWN) - { - ECORE_WINCE_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_WINCE_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_WINCE_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_WINCE_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_WINCE_EVENT_MOUSE_MOVE = ecore_event_type_new(); - 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(); - } - - _ecore_wince_init_count++; - - printf ("ecore_wince : instance + class bon\n"); - - return _ecore_wince_init_count; -} - -int -ecore_wince_shutdown() -{ - _ecore_wince_init_count++; - if (_ecore_wince_init_count > 0) return _ecore_wince_init_count; - if (!_ecore_wince_instance) return _ecore_wince_init_count; - - UnregisterClass(ECORE_WINCE_WINDOW_CLASS, _ecore_wince_instance); - FreeLibrary(_ecore_wince_instance); - _ecore_wince_instance = NULL; - - if (_ecore_wince_init_count < 0) _ecore_wince_init_count = 0; - - return _ecore_wince_init_count; -} +/*============================================================================* + * Local * + *============================================================================*/ /** - * 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 + * @cond LOCAL */ -EAPI void -ecore_wince_double_click_time_set(double t) -{ - if (t < 0.0) t = 0.0; - _ecore_wince_double_click_time = t; -} -/** - * Retrieves the double and triple click flag timeout. - * - * See @ref ecore_wince_double_click_time_set for more information. - * - * @return The timeout for double clicks in seconds. - */ -EAPI double -ecore_wince_double_click_time_get(void) -{ - return _ecore_wince_double_click_time; -} - -/** - * Return the last event time - */ -EAPI double -ecore_wince_current_time_get(void) -{ - return _ecore_wince_event_last_time; -} - - -/***** Private functions definitions *****/ +static int _ecore_wince_init_count = 0; LRESULT CALLBACK _ecore_wince_window_procedure(HWND window, @@ -193,53 +52,50 @@ _ecore_wince_window_procedure(HWND window, switch (data->message) { /* Keyboard input notifications */ + case WM_CHAR: + _ecore_wince_event_handle_key_press(data, 0); + break; case WM_HOTKEY: - printf (" * ecore message : keystroke down (hotkey)\n"); - _ecore_wince_event_handle_key_press(data); - return 0; + _ecore_wince_event_handle_key_press(data, 1); + break; case WM_KEYDOWN: - printf (" * ecore message : keystroke down\n"); - _ecore_wince_event_handle_key_press(data); - return 0; + case WM_SYSKEYDOWN: + _ecore_wince_event_handle_key_press(data, 1); + break; case WM_KEYUP: - printf (" * ecore message : keystroke up\n"); - _ecore_wince_event_handle_key_release(data); - return 0; + case WM_SYSKEYUP: + _ecore_wince_event_handle_key_release(data, 1); + break; case WM_SETFOCUS: - printf (" * ecore message : focus in\n"); _ecore_wince_event_handle_focus_in(data); - return 0; + break; case WM_KILLFOCUS: - printf (" * ecore message : focus out\n"); _ecore_wince_event_handle_focus_out(data); - return 0; + break; /* Mouse input notifications */ case WM_LBUTTONDOWN: - printf (" * ecore message : lbuttondown\n"); _ecore_wince_event_handle_button_press(data, 1); - return 0; + break; case WM_LBUTTONUP: - printf (" * ecore message : lbuttonup\n"); _ecore_wince_event_handle_button_release(data, 1); - return 0; + break; case WM_MOUSEMOVE: { - RECT rect; - struct _Ecore_WinCE_Window *w = NULL; + RECT rect; + Ecore_WinCE_Window *w = NULL; - w = (struct _Ecore_WinCE_Window *)GetWindowLong(window, GWL_USERDATA); - printf (" * ecore message : mouse move\n"); + w = (Ecore_WinCE_Window *)GetWindowLong(window, GWL_USERDATA); if (GetClientRect(window, &rect)) { POINT pt; - printf ("GetClientRect !!\n"); + INF("mouse in window"); + pt.x = LOWORD(data_param); pt.y = HIWORD(data_param); if (!PtInRect(&rect, pt)) { - printf ("pas dans rect...\n"); if (w->pointer_is_in) { w->pointer_is_in = 0; @@ -248,10 +104,8 @@ _ecore_wince_window_procedure(HWND window, } else { - printf ("dans rect... %d\n", w->pointer_is_in); if (!w->pointer_is_in) { - printf ("w->pointer_is_in a 0\n"); w->pointer_is_in = 1; _ecore_wince_event_handle_enter_notify(data); } @@ -259,65 +113,288 @@ _ecore_wince_window_procedure(HWND window, } else { - printf ("pas de GetClientRect !!\n"); + ERR("GetClientRect() failed"); } _ecore_wince_event_handle_motion_notify(data); - return 0; + break; } /* Window notifications */ case WM_CREATE: - { - RECT rect; - GetClientRect(window, &rect); - printf (" *** ecore message : create %ld %ld\n", - rect.right - rect.left, rect.bottom - rect.top); - } _ecore_wince_event_handle_create_notify(data); - return 0; + break; case WM_DESTROY: - printf (" * ecore message : destroy\n"); _ecore_wince_event_handle_destroy_notify(data); - return 0; + break; case WM_SHOWWINDOW: - { - RECT rect; - GetClientRect(window, &rect); - printf (" *** ecore message : show %ld %ld\n", - rect.right - rect.left, rect.bottom - rect.top); - } if ((data->data_param == SW_OTHERUNZOOM) || - (data->data_param == SW_OTHERUNZOOM)) - return 0; + (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); - return 0; + break; case WM_CLOSE: - printf (" * ecore message : close\n"); _ecore_wince_event_handle_delete_request(data); - return 0; + break; /* GDI notifications */ + case WM_ERASEBKGND: + return 1; case WM_PAINT: { - RECT rect; PAINTSTRUCT paint; - printf (" * ecore message : paint\n"); if (BeginPaint(window, &paint)) { - printf (" * ecore message : painting...\n"); data->update = paint.rcPaint; _ecore_wince_event_handle_expose(data); EndPaint(window, &paint); } - return 0; + 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 index 73fcd56..9afc062 100644 --- a/src/lib/ecore_wince/ecore_wince_event.c +++ b/src/lib/ecore_wince/ecore_wince_event.c @@ -1,260 +1,836 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif #include -#include /* for printf */ #define WIN32_LEAN_AND_MEAN #include #undef WIN32_LEAN_AND_MEAN -#include "Ecore.h" +#include +#include +#include + #include "Ecore_WinCE.h" #include "ecore_wince_private.h" +/*============================================================================* + * Local * + *============================================================================*/ -/***** Private declarations *****/ - -static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_window = NULL; -static Ecore_WinCE_Window *_ecore_wince_mouse_down_last_last_window = NULL; -static double _ecore_wince_mouse_down_last_time = 0; -static double _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 void _ecore_wince_event_free_key_down(void *data, - void *ev); +/** + * @cond LOCAL + */ -static void _ecore_wince_event_free_key_up(void *data, - void *ev); +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 int _ecore_wince_event_keystroke_get(int key, - char **keyname, - char **keysymbol, - char **keycompose); +static void +_ecore_wince_event_free_key_down(void *data __UNUSED__, + void *ev) +{ + Ecore_Event_Key *e; -static int _ecore_wince_event_char_get(int key, - char **keyname, - char **keysymbol, - char **keycompose); + 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; -/***** Global functions *****/ + 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); +} -void -_ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg) +static int +_ecore_wince_event_keystroke_get(int key, + Eina_Bool is_down, + char **keyname, + char **keysymbol, + char **keycompose) { - Ecore_WinCE_Event_Key_Down *e; + char *kn; + char *ks; + char *kc; + int previous_key_state; - e = (Ecore_WinCE_Event_Key_Down *)malloc(sizeof(Ecore_WinCE_Event_Key_Down)); - if (!e) return; + previous_key_state = msg->data_param & 0x40000000; - if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) - { - free(e); - return; - } + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); - if (!e->window) + switch (key) { - free(e); - return; + /* 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; } - e->time = (double)msg->time / 1000.0; - - _ecore_wince_event_last_time = e->time; - - ecore_event_add(ECORE_WINCE_EVENT_KEY_DOWN, e, _ecore_wince_event_free_key_down, NULL); -} - -void -_ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg) -{ - Ecore_WinCE_Event_Key_Up *e; - - e = (Ecore_WinCE_Event_Key_Up *)calloc(1, sizeof(Ecore_WinCE_Event_Key_Up)); - if (!e) return; - - if (!_ecore_wince_event_keystroke_get(LOWORD(msg->window_param), - &e->keyname, - &e->keysymbol, - &e->keycompose)) + *keyname = strdup(kn); + if (!*keyname) return 0; + *keysymbol = strdup(ks); + if (!*keysymbol) { - free(e); - return; + free(*keyname); + *keyname = NULL; + return 0; } - - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); - if (!e->window) + *keycompose = strdup(kc); + if (!*keycompose) { - free(e); - return; + free(*keyname); + free(*keysymbol); + *keyname = NULL; + *keysymbol = NULL; + return 0; } - e->time = (double)msg->time / 1000.0; - - _ecore_wince_event_last_time = e->time; - ecore_event_add(ECORE_WINCE_EVENT_KEY_UP, e, _ecore_wince_event_free_key_up, NULL); + return 1; } -void -_ecore_wince_event_handle_button_press(Ecore_WinCE_Callback_Data *msg, - int button) +static int +_ecore_wince_event_char_get(int key, + char **keyname, + char **keysymbol, + char **keycompose) { - Ecore_WinCE_Window *window; - - window = (void *)GetWindowLong(msg->window, GWL_USERDATA); - - { - Ecore_WinCE_Event_Mouse_Move *e; - - e = (Ecore_WinCE_Event_Mouse_Move *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Move)); - if (!e) return; - - e->window = window; - e->x = LOWORD(msg->data_param); - e->y = HIWORD(msg->data_param); - e->time = (double)msg->time / 1000.0; - - _ecore_wince_event_last_time = e->time; - _ecore_wince_event_last_window = e->window; - - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_MOVE, e, NULL, NULL); - } - - { - Ecore_WinCE_Event_Mouse_Button_Down *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.0; - _ecore_wince_mouse_down_last_last_time = 0.0; - } - - e = (Ecore_WinCE_Event_Mouse_Button_Down *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Button_Down)); - if (!e) return; + char kn[32]; + char ks[32]; + char kc[32]; - e->window = window; - e->button = button; - e->x = LOWORD(msg->data_param); - e->y = HIWORD(msg->data_param); - e->time = (double)msg->time / 1000.0; + *keyname = NULL; + *keysymbol = NULL; + *keycompose = NULL; - if (((e->time - _ecore_wince_mouse_down_last_time) <= _ecore_wince_double_click_time) && - (e->window == _ecore_wince_mouse_down_last_window)) - e->double_click = 1; + /* 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; - if (((e->time - _ecore_wince_mouse_down_last_last_time) <= (2.0 * _ecore_wince_double_click_time)) && - (e->window == _ecore_wince_mouse_down_last_window) && - (e->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; + 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->time; - _ecore_wince_event_last_window = e->window; + _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 = e->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->time; + _ecore_wince_mouse_down_last_time = e->timestamp; } - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, e, NULL, NULL); } - printf (" * ecore event button press\n"); } void _ecore_wince_event_handle_button_release(Ecore_WinCE_Callback_Data *msg, - int button) + int button) { Ecore_WinCE_Window *window; + INF("mouse button released"); + window = (void *)GetWindowLong(msg->window, GWL_USERDATA); { - Ecore_WinCE_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_WinCE_Event_Mouse_Move *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = window; + e->window = (Ecore_Window)window; + e->event_window = e->window; e->x = LOWORD(msg->data_param); e->y = HIWORD(msg->data_param); - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->time; - _ecore_wince_event_last_time = e->time; - _ecore_wince_event_last_window = e->window; + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { - Ecore_WinCE_Event_Mouse_Button_Up *e; + Ecore_Event_Mouse_Button *e; - e = (Ecore_WinCE_Event_Mouse_Button_Up *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Button_Up)); + e = (Ecore_Event_Mouse_Button *)calloc(1, sizeof(Ecore_Event_Mouse_Button)); if (!e) return; - e->window = window; - e->button = button; + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->time; _ecore_wince_mouse_up_count++; if ((_ecore_wince_mouse_up_count >= 2) && - ((e->time - _ecore_wince_mouse_down_last_time) <= _ecore_wince_double_click_time) && - (e->window == _ecore_wince_mouse_down_last_window)) + ((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->time - _ecore_wince_mouse_down_last_last_time) <= (2.0 * _ecore_wince_double_click_time)) && - (e->window == _ecore_wince_mouse_down_last_window) && - (e->window == _ecore_wince_mouse_down_last_last_window)) + ((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->time; - _ecore_wince_event_last_window = e->window; + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_BUTTON_UP, e, NULL, NULL); } - - printf (" * ecore event button release\n"); } void _ecore_wince_event_handle_motion_notify(Ecore_WinCE_Callback_Data *msg) { - Ecore_WinCE_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; + + INF("mouse moved"); - e = (Ecore_WinCE_Event_Mouse_Move *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = (void *)GetWindowLong(msg->window, GWL_USERDATA); + 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->time = (double)msg->time / 1000.0; + e->timestamp = msg->time; - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_MOVE, e, NULL, NULL); - printf (" * ecore event motion notify\n"); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } void @@ -262,24 +838,26 @@ _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); - printf (" * ecore event enter notify 0\n"); { - Ecore_WinCE_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_WinCE_Event_Mouse_Move *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = window; + e->window = (Ecore_Window)window; + e->event_window = e->window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->time; - _ecore_wince_event_last_time = e->time; - _ecore_wince_event_last_window = e->window; + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { @@ -291,13 +869,12 @@ _ecore_wince_event_handle_enter_notify(Ecore_WinCE_Callback_Data *msg) e->window = window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->time = msg->time; _ecore_wince_event_last_time = e->time; ecore_event_add(ECORE_WINCE_EVENT_MOUSE_IN, e, NULL, NULL); } - printf (" * ecore event enter notify 1\n"); } void @@ -305,23 +882,26 @@ _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_WinCE_Event_Mouse_Move *e; + Ecore_Event_Mouse_Move *e; - e = (Ecore_WinCE_Event_Mouse_Move *)calloc(1, sizeof(Ecore_WinCE_Event_Mouse_Move)); + e = (Ecore_Event_Mouse_Move *)calloc(1, sizeof(Ecore_Event_Mouse_Move)); if (!e) return; - e->window = window; + e->window = (Ecore_Window)window; + e->event_window = e->window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->timestamp = msg->time; - _ecore_wince_event_last_time = e->time; - _ecore_wince_event_last_window = e->window; + _ecore_wince_event_last_time = e->timestamp; + _ecore_wince_event_last_window = (Ecore_WinCE_Window *)e->window; - ecore_event_add(ECORE_WINCE_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_EVENT_MOUSE_MOVE, e, NULL, NULL); } { @@ -333,20 +913,21 @@ _ecore_wince_event_handle_leave_notify(Ecore_WinCE_Callback_Data *msg) e->window = window; e->x = msg->x; e->y = msg->y; - e->time = (double)msg->time / 1000.0; + e->time = msg->time; _ecore_wince_event_last_time = e->time; ecore_event_add(ECORE_WINCE_EVENT_MOUSE_OUT, e, NULL, NULL); } - printf (" * ecore event leave notify\n"); } void _ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg) { Ecore_WinCE_Event_Window_Focus_In *e; - struct _Ecore_WinCE_Window *window; + 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; @@ -358,8 +939,8 @@ _ecore_wince_event_handle_focus_in(Ecore_WinCE_Callback_Data *msg) return; } - if (window->resume) - window->resume(window->backend); + if (window->resume_cb) + window->resume_cb(window->backend); e->window = window; @@ -373,7 +954,9 @@ void _ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg) { Ecore_WinCE_Event_Window_Focus_Out *e; - struct _Ecore_WinCE_Window *window; + 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; @@ -384,8 +967,8 @@ _ecore_wince_event_handle_focus_out(Ecore_WinCE_Callback_Data *msg) free(e); return; } - if (window->suspend) - window->suspend(window->backend); + if (window->suspend_cb) + window->suspend_cb(window->backend); e->window = window; @@ -400,6 +983,8 @@ _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; @@ -414,7 +999,7 @@ _ecore_wince_event_handle_expose(Ecore_WinCE_Callback_Data *msg) e->y = msg->update.top; e->width = msg->update.right - msg->update.left; e->height = msg->update.bottom - msg->update.top; - printf (" * ecore : event expose %d %d\n", e->width, e->height); + INF("window expose size: %dx%d", e->width, e->height); e->time = _ecore_wince_event_last_time; @@ -426,6 +1011,8 @@ _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; @@ -446,6 +1033,8 @@ _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; @@ -467,6 +1056,8 @@ _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; @@ -487,6 +1078,8 @@ _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; @@ -507,6 +1100,8 @@ _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; @@ -522,323 +1117,7 @@ _ecore_wince_event_handle_delete_request(Ecore_WinCE_Callback_Data *msg) ecore_event_add(ECORE_WINCE_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); } +/*============================================================================* + * API * + *============================================================================*/ -/***** Private functions definitions *****/ - -static void -_ecore_wince_event_free_key_down(void *data, - void *ev) -{ - Ecore_WinCE_Event_Key_Down *e; - - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->keycompose) free(e->keycompose); - free(e); -} - -static void -_ecore_wince_event_free_key_up(void *data, - void *ev) -{ - Ecore_WinCE_Event_Key_Up *e; - - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->keycompose) free(e->keycompose); - free(e); -} - -static int -_ecore_wince_event_keystroke_get(int key, - char **keyname, - char **keysymbol, - char **keycompose) -{ - char *kn; - char *ks; - char *kc; - - *keyname = NULL; - *keysymbol = NULL; - *keycompose = NULL; - - switch (key) - { - /* Keystroke */ - case VK_PRIOR: - kn = "KP_Prior"; - ks = "KP_Prior"; - kc = ""; - break; - case VK_NEXT: - kn = "KP_Next"; - ks = "KP_Next"; - kc = ""; - break; - case VK_END: - kn = "KP_End"; - ks = "KP_End"; - kc = ""; - break; - case VK_HOME: - kn = "KP_Home"; - ks = "KP_Home"; - kc = ""; - break; - case VK_LEFT: - kn = "KP_Left"; - ks = "KP_Left"; - kc = ""; - break; - case VK_UP: - kn = "KP_Up"; - ks = "KP_Up"; - kc = ""; - break; - case VK_RIGHT: - kn = "KP_Right"; - ks = "KP_Right"; - kc = ""; - break; - case VK_DOWN: - kn = "KP_Down"; - ks = "KP_Down"; - kc = ""; - break; - case VK_INSERT: - kn = "KP_Insert"; - ks = "KP_Insert"; - kc = ""; - break; - case VK_DELETE: - kn = "KP_Delete"; - ks = "KP_Delete"; - kc = ""; - 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 */ - 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; - - *keyname = NULL; - *keysymbol = NULL; - *keycompose = NULL; - - switch (key) - { - case VK_APP3: - case VK_BACK: - strncpy(kn, "Backspace", 32); - strncpy(ks, "Backspace", 32); - kc = ""; - break; - case VK_APP4: - case VK_TAB: - strncpy(kn, "Tab", 32); - strncpy(ks, "Tab", 32); - kc = ""; - break; - case VK_APP5: - case 0x0a: - /* Line feed (Shift + Enter) */ - strncpy(kn, "LineFeed", 32); - strncpy(ks, "LineFeed", 32); - kc = ""; - break; - case VK_APP2: - case VK_RETURN: - strncpy(kn, "Return", 32); - strncpy(ks, "Return", 32); - kc = ""; - break; - case VK_APP1: - case VK_ESCAPE: - strncpy(kn, "Escape", 32); - strncpy(ks, "Escape", 32); - kc = ""; - break; - default: - /* displayable characters */ - printf (" * key : %d\n", key); - kn[0] = (TCHAR)key; - kn[1] = '\0'; - ks[0] = (TCHAR)key; - ks[1] = '\0'; - kc = ""; - 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; -} diff --git a/src/lib/ecore_wince/ecore_wince_private.h b/src/lib/ecore_wince/ecore_wince_private.h index 68aeed2..b506312 100644 --- a/src/lib/ecore_wince/ecore_wince_private.h +++ b/src/lib/ecore_wince/ecore_wince_private.h @@ -1,11 +1,28 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #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" @@ -24,30 +41,32 @@ struct _Ecore_WinCE_Callback_Data }; -typedef int (*ecore_wince_suspend) (int); -typedef int (*ecore_wince_resume) (int); +typedef int (*ecore_wince_suspend_cb) (int); +typedef int (*ecore_wince_resume_cb) (int); struct _Ecore_WinCE_Window { - HWND window; + HWND window; - int backend; - ecore_wince_suspend suspend; - ecore_wince_resume resume; + int backend; + ecore_wince_suspend_cb suspend_cb; + ecore_wince_resume_cb resume_cb; - unsigned int pointer_is_in : 1; + 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 double _ecore_wince_event_last_time; +extern long _ecore_wince_event_last_time; extern Ecore_WinCE_Window *_ecore_wince_event_last_window; -extern HINSTANCE _ecore_wince_instance; - -void _ecore_wince_event_handle_key_press(Ecore_WinCE_Callback_Data *msg); -void _ecore_wince_event_handle_key_release(Ecore_WinCE_Callback_Data *msg); +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); diff --git a/src/lib/ecore_wince/ecore_wince_window.c b/src/lib/ecore_wince/ecore_wince_window.c index de97069..49a6312 100644 --- a/src/lib/ecore_wince/ecore_wince_window.c +++ b/src/lib/ecore_wince/ecore_wince_window.c @@ -1,67 +1,146 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include -#include /* for printf */ +#ifdef HAVE_CONFIG_H +# include +#endif #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 + */ -/***** Private declarations *****/ typedef BOOL (__stdcall *UnregisterFunc1Proc)(UINT, UINT); -static int _ecore_wince_hardware_keys_register(HWND window); +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 *****/ +/*============================================================================* + * API * + *============================================================================*/ -Ecore_WinCE_Window * +/** + * @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) { - struct _Ecore_WinCE_Window *w; - HWND window; - RECT rect; + Ecore_WinCE_Window *w; + HWND window; + RECT rect; + + INF("creating window"); - w = (struct _Ecore_WinCE_Window *)calloc(1, sizeof(struct _Ecore_WinCE_Window)); + w = (Ecore_WinCE_Window *)calloc(1, sizeof(Ecore_WinCE_Window)); if (!w) - return NULL; + { + ERR("malloc() failed"); + return NULL; + } - SetRect(&rect, 0, 0, - GetSystemMetrics(SM_CXSCREEN), - GetSystemMetrics(SM_CYSCREEN)); + 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_VISIBLE | WS_POPUP, - rect.left, rect.top, - rect.right - rect.left, - rect.bottom - rect.top, - parent ? ((struct _Ecore_WinCE_Window *)parent)->window : NULL, + 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; } - SHFullScreen(window, - SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON); - if (!_ecore_wince_hardware_keys_register(window)) { + ERR("_ecore_wince_hardware_keys_register() failed"); DestroyWindow(window); free(w); return NULL; @@ -72,6 +151,7 @@ ecore_wince_window_new(Ecore_WinCE_Window *parent, SetLastError(0); if (!SetWindowLong(window, GWL_USERDATA, (LONG)w) && (GetLastError() != 0)) { + ERR("SetWindowLong() failed"); DestroyWindow(window); free(w); return NULL; @@ -82,76 +162,438 @@ ecore_wince_window_new(Ecore_WinCE_Window *parent, return w; } -void -ecore_wince_window_del(Ecore_WinCE_Window *window) +/** + * @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) { - Ecore_WinCE_Window *w; - if (!window) return; - DestroyWindow(((struct _Ecore_WinCE_Window *)window)->window); + INF("destroying window"); + + DestroyWindow(window->window); free(window); - fprintf (stderr, "ecore_wince_window_del\n"); } -void +/** + * @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; - fprintf (stderr, " ** ecore_wince_window_show %p\n", window); - ShowWindow(((struct _Ecore_WinCE_Window *)window)->window, SW_SHOWNORMAL); - UpdateWindow(((struct _Ecore_WinCE_Window *)window)->window); - SendMessage(((struct _Ecore_WinCE_Window *)window)->window, WM_SHOWWINDOW, 1, 0); + 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"); + } } -void +/** + * @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; - fprintf (stderr, " ** ecore_wince_window_hide %p\n", window); - ShowWindow(((struct _Ecore_WinCE_Window *)window)->window, SW_HIDE); - SendMessage(((struct _Ecore_WinCE_Window *)window)->window, WM_SHOWWINDOW, 0, 0); + INF("hiding window"); + + if (!ShowWindow(window->window, SW_HIDE)) + { + ERR("ShowWindow() failed"); + return; + } + if (!SendMessage(window->window, WM_SHOWWINDOW, 0, 0)) + { + ERR("SendMessage() failed"); + } } -void -ecore_wince_window_backend_set(Ecore_WinCE_Window *window, int backend) +/** + * @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) { - struct _Ecore_WinCE_Window *w; + wchar_t *wtitle; - if (!window) - return; + 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"); - w = (struct _Ecore_WinCE_Window *)window; - w->backend = backend; + if (!SetFocus(window->window)) + { + ERR("SetFocus() failed"); + } } -void -ecore_wince_window_suspend_set(Ecore_WinCE_Window *window, int (*suspend)(int)) +/** + * @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) { - struct _Ecore_WinCE_Window *w; + 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; - w = (struct _Ecore_WinCE_Window *)window; - w->suspend = suspend; + INF("setting backend"); + + window->backend = backend; } -void -ecore_wince_window_resume_set(Ecore_WinCE_Window *window, int (*resume)(int)) +/** + * @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)) { - struct _Ecore_WinCE_Window *w; + 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; - w = (struct _Ecore_WinCE_Window *)window; - w->resume = resume; + INF("setting resume callback"); + + window->resume_cb = resume_cb; } -void +/** + * @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, @@ -162,7 +604,8 @@ ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, int w; int h; - printf ("ecore_wince_window_geometry_get %p\n", window); + INF("getting window geometry"); + if (!window) { if (x) *x = 0; @@ -173,9 +616,10 @@ ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, return; } - if (!GetClientRect(((struct _Ecore_WinCE_Window *)window)->window, - &rect)) + if (!GetClientRect(window->window, &rect)) { + ERR("GetClientRect() failed"); + if (x) *x = 0; if (y) *y = 0; if (width) *width = 0; @@ -187,9 +631,10 @@ ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, w = rect.right - rect.left; h = rect.bottom - rect.top; - if (!GetWindowRect(((struct _Ecore_WinCE_Window *)window)->window, - &rect)) + if (!GetWindowRect(window->window, &rect)) { + ERR("GetWindowRect() failed"); + if (x) *x = 0; if (y) *y = 0; if (width) *width = 0; @@ -204,14 +649,29 @@ ecore_wince_window_geometry_get(Ecore_WinCE_Window *window, if (height) *height = h; } -void +/** + * @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; - printf ("ecore_wince_window_size_get %p\n", window); + INF("getting window size"); + if (!window) { if (width) *width = GetSystemMetrics(SM_CXSCREEN); @@ -220,9 +680,10 @@ ecore_wince_window_size_get(Ecore_WinCE_Window *window, return; } - if (!GetClientRect(((struct _Ecore_WinCE_Window *)window)->window, - &rect)) + if (!GetClientRect(window->window, &rect)) { + ERR("GetClientRect() failed"); + if (width) *width = 0; if (height) *height = 0; } @@ -231,45 +692,136 @@ ecore_wince_window_size_get(Ecore_WinCE_Window *window, if (height) *height = rect.bottom - rect.top; } -void * -ecore_wince_window_window_get(Ecore_WinCE_Window *window) +/** + * @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) { - struct _Ecore_WinCE_Window *w; - - if (!window) - return NULL; + HWND task_bar; - return ((struct _Ecore_WinCE_Window *)window)->window; -} + if (!window) return; + if (((window->fullscreen) && (on)) || + ((!window->fullscreen) && (!on))) + return; -/***** Private functions definitions *****/ + INF("setting fullscreen: %s", on ? "yes" : "no"); -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) - return 0; + window->fullscreen = !!on; - unregister_fct = (UnregisterFunc1Proc)GetProcAddress(core_dll, L"UnregisterFunc1"); - if (!unregister_fct) + if (on) { - FreeLibrary(core_dll); - return 0; + /* 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"); + } } - - for (i = 0xc1; i <= 0xcf; i++) + else { - unregister_fct(MOD_WIN, i); - RegisterHotKey(window, i, MOD_WIN, i); + /* 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"); + } } - - FreeLibrary(core_dll); - - return 1; } + +/** + * @} + */ diff --git a/src/lib/ecore_x/Ecore_X.h b/src/lib/ecore_x/Ecore_X.h index 050e9bc..b3fc0fa 100644 --- a/src/lib/ecore_x/Ecore_X.h +++ b/src/lib/ecore_x/Ecore_X.h @@ -1,30 +1,29 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #ifndef _ECORE_X_H #define _ECORE_X_H +#include + #ifdef EAPI # undef EAPI -#endif +#endif // ifdef EAPI + #ifdef _MSC_VER # ifdef BUILDING_DLL # define EAPI __declspec(dllexport) -# else +# else // ifdef BUILDING_DLL # define EAPI __declspec(dllimport) -# endif -#else +# endif // ifdef BUILDING_DLL +#else // ifdef _MSC_VER # ifdef __GNUC__ # if __GNUC__ >= 4 # define EAPI __attribute__ ((visibility("default"))) -# else +# else // if __GNUC__ >= 4 # define EAPI -# endif -# else +# endif // if __GNUC__ >= 4 +# else // ifdef __GNUC__ # define EAPI -# endif -#endif +# endif // ifdef __GNUC__ +#endif // ifdef _MSC_VER #include @@ -40,87 +39,119 @@ * @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 +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_Visual; -#else -typedef void * Ecore_X_Visual; +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_Pixmap; -typedef Ecore_X_ID Ecore_X_Drawable; -#ifdef HAVE_ECORE_X_XCB -typedef Ecore_X_ID Ecore_X_GC; -#else -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 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 +#endif // ifdef __cplusplus -typedef struct _Ecore_X_Rectangle { - int x, y; +typedef struct _Ecore_X_Rectangle +{ + int x, y; unsigned int width, height; } Ecore_X_Rectangle; -typedef struct _Ecore_X_Icon { +typedef struct _Ecore_X_Icon +{ unsigned int width, height; unsigned int *data; } Ecore_X_Icon; -typedef enum _Ecore_X_Window_State { - /** The window is iconified. */ - ECORE_X_WINDOW_STATE_ICONIFIED, - /** The window is a modal dialog box. */ - ECORE_X_WINDOW_STATE_MODAL, - /** The window manager should keep the window's position fixed - * even if the virtual desktop scrolls. */ - ECORE_X_WINDOW_STATE_STICKY, - /** The window has the maximum vertical size. */ - ECORE_X_WINDOW_STATE_MAXIMIZED_VERT, - /** The window has the maximum horizontal size. */ - ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ, - /** The window is shaded. */ - ECORE_X_WINDOW_STATE_SHADED, - /** The window should not be included in the taskbar. */ - ECORE_X_WINDOW_STATE_SKIP_TASKBAR, - /** The window should not be included in the pager. */ - ECORE_X_WINDOW_STATE_SKIP_PAGER, - /** The window is invisible (i.e. minimized/iconified) */ - ECORE_X_WINDOW_STATE_HIDDEN, - /** The window should fill the entire screen and have no - * window border/decorations */ - ECORE_X_WINDOW_STATE_FULLSCREEN, - /* The following are not documented because they are not - * intended for use in applications. */ - ECORE_X_WINDOW_STATE_ABOVE, - ECORE_X_WINDOW_STATE_BELOW, - /* FIXME: Documentation */ - ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION, - /* Unknown state */ - ECORE_X_WINDOW_STATE_UNKNOWN +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 +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 { +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, @@ -128,35 +159,99 @@ typedef enum _Ecore_X_Window_Stack_Mode { ECORE_X_WINDOW_STACK_OPPOSITE = 4 } Ecore_X_Window_Stack_Mode; -typedef enum _Ecore_X_Randr_Rotation { - ECORE_X_RANDR_ROT_0 = (1 << 0), - ECORE_X_RANDR_ROT_90 = (1 << 1), - ECORE_X_RANDR_ROT_180 = (1 << 2), - ECORE_X_RANDR_ROT_270 = (1 << 3), - ECORE_X_RANDR_FLIP_X = (1 << 4), - ECORE_X_RANDR_FLIP_Y = (1 << 5) -} Ecore_X_Randr_Rotation; - -#define ECORE_X_SELECTION_TARGET_TARGETS "TARGETS" -#define ECORE_X_SELECTION_TARGET_TEXT "TEXT" +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_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 +#define ECORE_X_DND_VERSION 5 -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; - -typedef enum _Ecore_X_Selection { +typedef enum _Ecore_X_Selection +{ ECORE_X_SELECTION_PRIMARY, ECORE_X_SELECTION_SECONDARY, ECORE_X_SELECTION_XDND, - ECORE_X_SELECTION_CLIPBOARD + ECORE_X_SELECTION_CLIPBOARD, + ECORE_X_SELECTION_OTHER } Ecore_X_Selection; typedef enum _Ecore_X_Event_Mode @@ -181,239 +276,212 @@ typedef enum _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_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_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 +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_CLIP, + ECORE_X_SHAPE_INPUT } Ecore_X_Shape_Type; -typedef struct _Ecore_X_Event_Key_Down Ecore_X_Event_Key_Down; -typedef struct _Ecore_X_Event_Key_Up Ecore_X_Event_Key_Up; -typedef struct _Ecore_X_Event_Mouse_Button_Down Ecore_X_Event_Mouse_Button_Down; -typedef struct _Ecore_X_Event_Mouse_Button_Up Ecore_X_Event_Mouse_Button_Up; -typedef struct _Ecore_X_Event_Mouse_Move Ecore_X_Event_Mouse_Move; -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_Mouse_Wheel Ecore_X_Event_Mouse_Wheel; -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_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_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_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_Window_Delete_Request Ecore_X_Event_Window_Delete_Request; -typedef struct _Ecore_X_Event_Window_Prop_Title_Change Ecore_X_Event_Window_Prop_Title_Change; -typedef struct _Ecore_X_Event_Window_Prop_Visible_Title_Change Ecore_X_Event_Window_Prop_Visible_Title_Change; -typedef struct _Ecore_X_Event_Window_Prop_Icon_Name_Change Ecore_X_Event_Window_Prop_Icon_Name_Change; -typedef struct _Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change; -typedef struct _Ecore_X_Event_Window_Prop_Client_Machine_Change Ecore_X_Event_Window_Prop_Client_Machine_Change; -typedef struct _Ecore_X_Event_Window_Prop_Name_Class_Change Ecore_X_Event_Window_Prop_Name_Class_Change; -typedef struct _Ecore_X_Event_Window_Prop_Pid_Change Ecore_X_Event_Window_Prop_Pid_Change; -typedef struct _Ecore_X_Event_Window_Prop_Desktop_Change Ecore_X_Event_Window_Prop_Desktop_Change; - -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; - -struct _Ecore_X_Event_Key_Down -{ - char *keyname; - char *keysymbol; - char *key_compose; - int modifiers; - int same_screen; - Ecore_X_Window win; - Ecore_X_Window event_win; - Ecore_X_Window root_win; - Ecore_X_Time time; -}; - -struct _Ecore_X_Event_Key_Up -{ - char *keyname; - char *keysymbol; - char *key_compose; - int modifiers; - int same_screen; - Ecore_X_Window win; - Ecore_X_Window event_win; - Ecore_X_Window root_win; - Ecore_X_Time time; -}; - -struct _Ecore_X_Event_Mouse_Button_Down -{ - int button; - 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_Time time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; - -struct _Ecore_X_Event_Mouse_Button_Up -{ - int button; - 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_Time time; - unsigned int double_click : 1; - unsigned int triple_click : 1; -}; +typedef enum _Ecore_X_Mapping_Type +{ + ECORE_X_MAPPING_MODIFIER, + ECORE_X_MAPPING_KEYBOARD, + ECORE_X_MAPPING_MOUSE +} Ecore_X_Mapping_Type; -struct _Ecore_X_Event_Mouse_Move +typedef enum _Ecore_X_Randr_Property_Change { - 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_Time time; -}; + 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; - int same_screen; - struct { - 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; + 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_Mouse_Wheel -{ - int direction; /* 0 = default up/down wheel FIXME: more wheel types */ - int z; /* ...,-2,-1 = down, 1,2,... = up */ - int modifiers; - int x, y; - int same_screen; - - struct { + int same_screen; + struct + { int x, y; } root; - - Ecore_X_Window win; - Ecore_X_Window event_win; - Ecore_X_Window root_win; - Ecore_X_Time time; + 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 @@ -434,266 +502,318 @@ struct _Ecore_X_Event_Window_Focus_Out struct _Ecore_X_Event_Window_Keymap { - Ecore_X_Window win; + 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; + 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; + Ecore_X_Window win; + int fully_obscured; + Ecore_X_Time time; }; struct _Ecore_X_Event_Window_Create { - Ecore_X_Window win; - int override; - Ecore_X_Time time; + 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_Time time; + 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_Time time; + 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_Time time; + 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; + 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 parent; - Ecore_X_Time time; + 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 abovewin; - int x, y, w, h; - int border; - unsigned int override : 1; - unsigned int from_wm : 1; - Ecore_X_Time time; + 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 abovewin; - int x, y, w, h; - int border; + 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; + unsigned long value_mask; + Ecore_X_Time time; }; struct _Ecore_X_Event_Window_Gravity { - Ecore_X_Window win; - Ecore_X_Time time; + 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; + 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 win; + Ecore_X_Window event_win; Ecore_X_Window_Stack_Mode detail; - Ecore_X_Time time; + Ecore_X_Time time; }; struct _Ecore_X_Event_Window_Stack_Request { - Ecore_X_Window win; - Ecore_X_Window parent; + Ecore_X_Window win; + Ecore_X_Window parent; Ecore_X_Window_Stack_Mode detail; - Ecore_X_Time time; + Ecore_X_Time time; }; struct _Ecore_X_Event_Window_Property { - Ecore_X_Window win; - Ecore_X_Atom atom; - Ecore_X_Time time; + 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; - int installed; + 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; + 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; - char *target; - void *data; + 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 + 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); + 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; + char **files; + int num_files; }; struct _Ecore_X_Selection_Data_Text { Ecore_X_Selection_Data data; - char *text; + char *text; }; struct _Ecore_X_Selection_Data_Targets { Ecore_X_Selection_Data data; - char **targets; - int num_targets; + char **targets; + int num_targets; }; struct _Ecore_X_Event_Xdnd_Enter { - Ecore_X_Window win, source; + Ecore_X_Window win, source; - char **types; - int num_types; + char **types; + int num_types; }; struct _Ecore_X_Event_Xdnd_Position { - Ecore_X_Window win, source; - struct { + 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; - Ecore_X_Atom action; }; struct _Ecore_X_Event_Xdnd_Status { - Ecore_X_Window win, target; - int will_accept; - Ecore_X_Rectangle rectangle; - Ecore_X_Atom action; + 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; + Ecore_X_Window win, source; }; struct _Ecore_X_Event_Xdnd_Drop { - Ecore_X_Window win, source; - Ecore_X_Atom action; - struct { + 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; - int completed; - Ecore_X_Atom action; + 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; + 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_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; - int on; - Ecore_X_Time time; + Ecore_X_Window win; + Eina_Bool on : 1; + Ecore_X_Time time; }; struct _Ecore_X_Event_Sync_Counter { - Ecore_X_Time time; + Ecore_X_Time time; }; struct _Ecore_X_Event_Sync_Alarm @@ -702,78 +822,123 @@ struct _Ecore_X_Event_Sync_Alarm 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, root; - int width, height; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + Ecore_X_Window win; + long desktop; + Ecore_X_Time time; }; struct _Ecore_X_Event_Startup_Sequence { - Ecore_X_Window win; + Ecore_X_Window win; }; struct _Ecore_X_Event_Window_Move_Resize_Request @@ -795,31 +960,37 @@ struct _Ecore_X_Event_Window_State_Request struct _Ecore_X_Event_Frame_Extents_Request { - Ecore_X_Window win; + Ecore_X_Window win; }; struct _Ecore_X_Event_Ping { - Ecore_X_Window win; - Ecore_X_Window event_win; - Ecore_X_Time time; + 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; + 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_KEY_DOWN; -EAPI extern int ECORE_X_EVENT_KEY_UP; -EAPI extern int ECORE_X_EVENT_MOUSE_BUTTON_DOWN; -EAPI extern int ECORE_X_EVENT_MOUSE_BUTTON_UP; -EAPI extern int ECORE_X_EVENT_MOUSE_MOVE; +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_MOUSE_WHEEL; 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; @@ -840,28 +1011,30 @@ 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_PROP_TITLE_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE; -EAPI extern int ECORE_X_EVENT_WINDOW_PROP_DESKTOP_CHANGE; -*/ EAPI extern int ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST; EAPI extern int ECORE_X_EVENT_WINDOW_STATE_REQUEST; @@ -872,6 +1045,10 @@ 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; @@ -880,63 +1057,66 @@ 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; -EAPI extern int ECORE_X_MODIFIER_CTRL; -EAPI extern int ECORE_X_MODIFIER_ALT; -EAPI extern int ECORE_X_MODIFIER_WIN; +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; + +EAPI extern int ECORE_X_RAW_BUTTON_PRESS; /**< @since 1.8 */ +EAPI extern int ECORE_X_RAW_BUTTON_RELEASE; /**< @since 1.8 */ +EAPI extern int ECORE_X_RAW_MOTION; /**< @since 1.8 */ -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 +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, +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 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 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 + /** 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 enum _Ecore_X_Window_State_Hint { +/** + * @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, @@ -947,421 +1127,381 @@ typedef enum _Ecore_X_Window_State_Hint { 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_ICONIC } Ecore_X_Window_State_Hint; -typedef enum _Ecore_X_Window_Type { - 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_UNKNOWN +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 +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) +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 +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_BELOW 2 #define ECORE_X_WINDOW_LAYER_NORMAL 4 -#define ECORE_X_WINDOW_LAYER_ABOVE 6 +#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_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 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 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 int 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 void ecore_x_selection_primary_prefetch(void); -EAPI void ecore_x_selection_primary_fetch(void); -EAPI int ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size); -EAPI int ecore_x_selection_primary_clear(void); -EAPI void ecore_x_selection_secondary_prefetch(void); -EAPI void ecore_x_selection_secondary_fetch(void); -EAPI int ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size); -EAPI int ecore_x_selection_secondary_clear(void); -EAPI void ecore_x_selection_xdnd_prefetch(void); -EAPI void ecore_x_selection_xdnd_fetch(void); -EAPI int ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size); -EAPI int ecore_x_selection_xdnd_clear(void); -EAPI void ecore_x_selection_clipboard_prefetch(void); -EAPI void ecore_x_selection_clipboard_fetch(void); -EAPI int ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size); -EAPI int 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 int ecore_x_selection_convert(Ecore_X_Atom selection, Ecore_X_Atom target, void **data_ret); -EAPI void ecore_x_selection_converter_add(char *target, int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret)); -EAPI void ecore_x_selection_converter_atom_add(Ecore_X_Atom target, int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret)); -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_dnd_aware_set(Ecore_X_Window win, int on); -EAPI void ecore_x_dnd_version_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_dnd_version_get_fetch(void); -EAPI int ecore_x_dnd_version_get(Ecore_X_Window win); -EAPI void ecore_x_dnd_type_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_dnd_type_get_fetch(void); -EAPI int 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, int on); -EAPI void ecore_x_dnd_types_set(Ecore_X_Window win, 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 void ecore_x_dnd_begin_prefetch(Ecore_X_Window source); -EAPI void ecore_x_dnd_begin_fetch(void); -EAPI int ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size); -EAPI int ecore_x_dnd_drop(void); -EAPI void ecore_x_dnd_send_status(int will_accept, int suppress, Ecore_X_Rectangle rectangle, Ecore_X_Atom action); -EAPI void ecore_x_dnd_send_finished(void); - -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_del(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 void ecore_x_get_input_focus_prefetch(void); -EAPI void ecore_x_get_input_focus_fetch(void); -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, int 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 void ecore_x_query_tree_prefetch(Ecore_X_Window window); -EAPI void ecore_x_query_tree_fetch(void); -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, int override); - -EAPI void ecore_x_window_prop_card32_set(Ecore_X_Window win, Ecore_X_Atom atom, - unsigned int *val, unsigned int num); -EAPI void ecore_x_window_prop_card32_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom); -EAPI void ecore_x_window_prop_card32_get_fetch(void); -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 void ecore_x_window_prop_xid_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom, - Ecore_X_Atom type); -EAPI void ecore_x_window_prop_xid_get_fetch(void); -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 void ecore_x_window_prop_atom_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom); -EAPI void ecore_x_window_prop_atom_get_fetch(void); -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 void ecore_x_window_prop_window_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom); -EAPI void ecore_x_window_prop_window_get_fetch(void); -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 void ecore_x_window_prop_property_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom property, - Ecore_X_Atom type); -EAPI void ecore_x_window_prop_property_get_fetch(void); -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 void ecore_x_window_prop_list_prefetch(Ecore_X_Window window); -EAPI void ecore_x_window_prop_list_fetch(void); -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 void ecore_x_window_prop_string_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom type); -EAPI void ecore_x_window_prop_string_get_fetch(void); -EAPI char *ecore_x_window_prop_string_get(Ecore_X_Window win, Ecore_X_Atom type); -EAPI int 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_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_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_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num); -EAPI void ecore_x_window_shape_rectangles_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_window_shape_rectangles_get_fetch(void); -EAPI Ecore_X_Rectangle *ecore_x_window_shape_rectangles_get(Ecore_X_Window win, int *num_ret); -EAPI void ecore_x_window_shape_events_select(Ecore_X_Window win, int 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_del(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); -EAPI void ecore_x_gc_del(Ecore_X_GC gc); - -EAPI int 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 int ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, const void *data, int len); -EAPI int ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y); -EAPI int ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b); -EAPI int ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b); - -EAPI void ecore_x_drawable_geometry_get_prefetch(Ecore_X_Drawable drawable); -EAPI void ecore_x_drawable_geometry_get_fetch(void); -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 int 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); - +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 Eina_Bool ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret, Ecore_X_Atom *targprop, int *s); /** @since 1.8 */ + +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 int 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 void ecore_x_atom_get_prefetch(const char *name); -EAPI void ecore_x_atom_get_fetch(void); -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 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 *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, - int 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, - int is_urgent); -EAPI int ecore_x_icccm_hints_get(Ecore_X_Window win, - int *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, - int *is_urgent); -EAPI void ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, - int 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 int ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, - int *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_set(Ecore_X_Window win, - Ecore_X_WM_Protocol protocol, - int on); -EAPI int 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); - +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 { @@ -1389,342 +1529,879 @@ 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_FULL_APPLICATION_MODAL = 3 } Ecore_X_MWM_Hint_Input; -EAPI void ecore_x_mwm_hints_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_mwm_hints_get_fetch(void); -EAPI int 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, int borderless); +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 void ecore_x_netwm_supported_get_prefetch(Ecore_X_Window root); -EAPI void ecore_x_netwm_supported_get_fetch(void); -EAPI int 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 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, int 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 void ecore_x_netwm_name_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_name_get_fetch(void); -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 void ecore_x_netwm_startup_id_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_startup_id_get_fetch(void); -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 void ecore_x_netwm_visible_name_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_visible_name_get_fetch(void); -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 void ecore_x_netwm_icon_name_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_icon_name_get_fetch(void); -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 void ecore_x_netwm_visible_icon_name_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_visible_icon_name_get_fetch(void); -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 void ecore_x_netwm_desktop_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_desktop_get_fetch(void); -EAPI int 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 void ecore_x_netwm_strut_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_strut_get_fetch(void); -EAPI int 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 void ecore_x_netwm_strut_partial_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_strut_partial_get_fetch(void); -EAPI int 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_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_icons_get_fetch(void); -EAPI int 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 void ecore_x_netwm_icon_geometry_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_icon_geometry_get_fetch(void); -EAPI int 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 void ecore_x_netwm_pid_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_pid_get_fetch(void); -EAPI int ecore_x_netwm_pid_get(Ecore_X_Window win, int *pid); -EAPI void ecore_x_netwm_handled_icons_set(Ecore_X_Window win); -EAPI void ecore_x_netwm_handled_icons_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_handled_icons_get_fetch(void); -EAPI int 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 void ecore_x_netwm_user_time_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_user_time_get_fetch(void); -EAPI int 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 void ecore_x_netwm_window_state_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_window_state_get_fetch(void); -EAPI int 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 void ecore_x_netwm_window_type_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_window_type_get_fetch(void); -EAPI int 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 int 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 void ecore_x_netwm_allowed_action_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_allowed_action_get_fetch(void); -EAPI int 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 void ecore_x_netwm_opacity_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_opacity_get_fetch(void); -EAPI int 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 void ecore_x_netwm_frame_size_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_frame_size_get_fetch(void); -EAPI int ecore_x_netwm_frame_size_get(Ecore_X_Window win, int *fl, int *fr, int *ft, int *fb); -EAPI void ecore_x_netwm_sync_counter_get_prefetch(Ecore_X_Window window); -EAPI void ecore_x_netwm_sync_counter_get_fetch(void); -EAPI int 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, int set); -EAPI void ecore_x_netwm_desktop_request_send(Ecore_X_Window win, Ecore_X_Window root, unsigned int desktop); - - - - -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, int is_keyboard); -EAPI int 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); +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_access_action_up_send(Ecore_X_Window win); +EAPI void ecore_x_e_illume_access_action_down_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 */ - -EAPI void ecore_x_xinerama_query_screens_prefetch(void); -EAPI void ecore_x_xinerama_query_screens_fetch(void); -EAPI int ecore_x_xinerama_screen_count_get(void); -EAPI int ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, int *w, int *h); - -EAPI int ecore_x_screensaver_event_available_get(void); -EAPI void ecore_x_screensaver_idle_time_prefetch(void); -EAPI void ecore_x_screensaver_idle_time_fetch(void); -EAPI int ecore_x_screensaver_idle_time_get(void); -EAPI void ecore_x_get_screensaver_prefetch(void); -EAPI void ecore_x_get_screensaver_fetch(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(int on); - /* FIXME: these funcs need categorising */ typedef struct _Ecore_X_Window_Attributes { - Ecore_X_Window root; - int x, y, w, h; - int border; - int depth; - unsigned char visible : 1; - unsigned char viewable : 1; - unsigned char override : 1; - unsigned char input_only : 1; - unsigned char save_under : 1; - struct { - Ecore_X_Event_Mask mine; - Ecore_X_Event_Mask all; - Ecore_X_Event_Mask no_propagate; + 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; + 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 void ecore_x_get_window_attributes_prefetch(Ecore_X_Window window); -EAPI void ecore_x_get_window_attributes_fetch(void); -EAPI int 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 int ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold); -EAPI void ecore_x_pointer_control_get_prefetch(void); -EAPI void ecore_x_pointer_control_get_fetch(void); -EAPI int ecore_x_pointer_control_get(int *accel_num, int *accel_denom, int *threshold); -EAPI int ecore_x_pointer_grab(Ecore_X_Window win); -EAPI int ecore_x_pointer_confine_grab(Ecore_X_Window win); -EAPI void ecore_x_pointer_ungrab(void); -EAPI int ecore_x_pointer_warp(Ecore_X_Window win, int x, int y); -EAPI int 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(int (*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_prefetch(Ecore_X_Window window); -EAPI void ecore_x_pointer_xy_get_fetch(void); -EAPI void ecore_x_pointer_xy_get(Ecore_X_Window win, int *x, int *y); - -/* ecore_x_sync.c */ -EAPI Ecore_X_Sync_Alarm ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter); -EAPI int ecore_x_sync_alarm_free(Ecore_X_Sync_Alarm alarm); +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 */ -typedef struct _Ecore_X_Screen_Size Ecore_X_Screen_Size; -struct _Ecore_X_Screen_Size -{ - int width, height; -}; -typedef struct _Ecore_X_Screen_Refresh_Rate Ecore_X_Screen_Refresh_Rate; -struct _Ecore_X_Screen_Refresh_Rate -{ - int rate; -}; +/* 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. + */ -EAPI int ecore_x_randr_query(); -EAPI int ecore_x_randr_events_select(Ecore_X_Window win, int on); -EAPI void ecore_x_randr_get_screen_info_prefetch(Ecore_X_Window window); -EAPI void ecore_x_randr_get_screen_info_fetch(void); -EAPI Ecore_X_Randr_Rotation ecore_x_randr_screen_rotations_get(Ecore_X_Window root); -EAPI Ecore_X_Randr_Rotation ecore_x_randr_screen_rotation_get(Ecore_X_Window root); -EAPI void ecore_x_randr_screen_rotation_set(Ecore_X_Window root, Ecore_X_Randr_Rotation rot); -EAPI Ecore_X_Screen_Size *ecore_x_randr_screen_sizes_get(Ecore_X_Window root, int *num); -EAPI Ecore_X_Screen_Size ecore_x_randr_current_screen_size_get(Ecore_X_Window root); -EAPI int ecore_x_randr_screen_size_set(Ecore_X_Window root, Ecore_X_Screen_Size size); +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); -EAPI Ecore_X_Screen_Refresh_Rate *ecore_x_randr_screen_refresh_rates_get(Ecore_X_Window root, int size_id, int *num); -EAPI Ecore_X_Screen_Refresh_Rate ecore_x_randr_current_screen_refresh_rate_get(Ecore_X_Window root); +/** + * @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 */ -EAPI int ecore_x_randr_screen_refresh_rate_set(Ecore_X_Window root, Ecore_X_Screen_Size size, Ecore_X_Screen_Refresh_Rate rate); +/** + * @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; +typedef Ecore_X_ID Ecore_X_Picture; /* XFixes Extension Support */ -typedef Ecore_X_ID Ecore_X_Region; +typedef Ecore_X_ID Ecore_X_Region; -typedef enum _Ecore_X_Region_Type { - ECORE_X_REGION_BOUNDING, - ECORE_X_REGION_CLIP +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_del(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 void ecore_x_region_fetch_prefetch(Ecore_X_Region region); -EAPI void ecore_x_region_fetch_fetch(void); -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); +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 int ecore_x_composite_query(void); +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 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 +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; - -EAPI int 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_del(Ecore_X_Damage damage); -EAPI void ecore_x_damage_subtract(Ecore_X_Damage damage, Ecore_X_Region repair, Ecore_X_Region parts); - -EAPI int ecore_x_screen_is_composited(int screen); - -EAPI int ecore_x_dpms_query(void); -EAPI void ecore_x_dpms_capable_get_prefetch(void); -EAPI void ecore_x_dpms_capable_get_fetch(void); -EAPI int ecore_x_dpms_capable_get(void); -EAPI void ecore_x_dpms_enable_get_prefetch(void); -EAPI void ecore_x_dpms_enable_get_fetch(void); -EAPI int ecore_x_dpms_enabled_get(void); -EAPI void ecore_x_dpms_enabled_set(int enabled); -EAPI void ecore_x_dpms_timeouts_get_prefetch(void); -EAPI void ecore_x_dpms_timeouts_get_fetch(void); -EAPI void ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned int *off); -EAPI int 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 int ecore_x_test_fake_key_down(const char *key); -EAPI int ecore_x_test_fake_key_up(const char *key); -EAPI int ecore_x_test_fake_key_press(const char *key); -EAPI const char *ecore_x_keysym_string_get(int keysym); - +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_input_raw_select(Ecore_X_Window win); /**< @since 1.8 */ + +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 +#endif // ifdef __cplusplus + +#include +#include -#endif +#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 index 4d1253d..ca6351d 100644 --- a/src/lib/ecore_x/Ecore_X_Atoms.h +++ b/src/lib/ecore_x/Ecore_X_Atoms.h @@ -1,6 +1,3 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ #ifndef _ECORE_X_ATOMS_H #define _ECORE_X_ATOMS_H @@ -18,6 +15,8 @@ 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; @@ -45,7 +44,7 @@ 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; @@ -126,6 +125,12 @@ 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; @@ -154,6 +159,8 @@ 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; @@ -180,19 +187,106 @@ 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; -/* currenly E specific virtual keyboard extension, aim to submit to netwm spec +/* 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; +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_ILLUME_ACCESS_ACTION_UP; +EAPI extern Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN; + +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 index af2e97a..807541e 100644 --- a/src/lib/ecore_x/Ecore_X_Cursor.h +++ b/src/lib/ecore_x/Ecore_X_Cursor.h @@ -6,81 +6,82 @@ * @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_BOTTOM_LEFT_CORNER 12 +#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 +#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 +#endif // ifndef _ECORE_X_CURSOR_H diff --git a/src/lib/ecore_x/Makefile.am b/src/lib/ecore_x/Makefile.am index 9e6a8fd..b14fc7d 100644 --- a/src/lib/ecore_x/Makefile.am +++ b/src/lib/ecore_x/Makefile.am @@ -1,7 +1,5 @@ MAINTAINERCLEANFILES = Makefile.in -if BUILD_ECORE_X - SUBDIRS = xlib xcb if BUILD_ECORE_X_XCB @@ -12,25 +10,21 @@ endif AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_srcdir)/src/lib/ecore_txt \ -I$(top_builddir)/src/lib/ecore \ --I$(top_builddir)/src/lib/ecore_txt +@EINA_CFLAGS@ lib_LTLIBRARIES = libecore_x.la libecore_x_la_SOURCES = -libecore_x_la_LIBADD = $(DEP) - -libecore_x_la_LDFLAGS = -version-info @version_info@ - +libecore_x_la_LIBADD = $(DEP) @EINA_LIBS@ +libecore_x_la_LDFLAGS = -version-info @version_info@ @release_info@ libecore_x_la_DEPENDENCIES = $(DEP) -include_HEADERS = \ +includes_HEADERS = \ Ecore_X.h \ Ecore_X_Atoms.h \ Ecore_X_Cursor.h - -endif +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 index 08e9b2f..df1f1a7 100644 --- a/src/lib/ecore_x/ecore_x_atoms_decl.h +++ b/src/lib/ecore_x/ecore_x_atoms_decl.h @@ -1,83 +1,85 @@ /* 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_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; +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; +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; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE = 0; /* old Gnome atom */ -EAPI Ecore_X_Atom ECORE_X_ATOM_WIN_LAYER = 0; +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 */ +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; +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; +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; +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; +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; +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; +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) */ @@ -85,135 +87,529 @@ EAPI Ecore_X_Atom ECORE_X_ATOM_MOTIF_WM_HINTS = 0; * 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; +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_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; +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; +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 = 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; +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_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; +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; +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; +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; +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; - -/* currenly E specific virtual keyboard extension, aim to submit to netwm spec +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 = 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_ILLUME_ACCESS_ACTION_UP = 0; +EAPI Ecore_X_Atom ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN = 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_WINDOW_STATE", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE }, + { "_E_ILLUME_WINDOW_STATE_NORMAL", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_NORMAL }, + { "_E_ILLUME_WINDOW_STATE_FLOATING", &ECORE_X_ATOM_E_ILLUME_WINDOW_STATE_FLOATING }, + { "_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_ILLUME_ACCESS_ACTION_UP", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP }, + { "_E_ILLUME_ACCESS_ACTION_DOWN", &ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN }, + { "_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 }, + + { "_E_PROFILE", &ECORE_X_ATOM_E_PROFILE }, + { "_E_PROFILE_LIST", &ECORE_X_ATOM_E_PROFILE_LIST } + + /* SLP additions after the comma */ , + + /* for sliding window */ + { "_E_ILLUME_SLIDING_WIN_STATE", &ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_STATE }, + { "_E_ILLUME_SLIDING_WIN_GEOMETRY", &ECORE_X_ATOM_E_ILLUME_SLIDING_WIN_GEOMETRY }, + + /* for SDB(Samsung Debug Bridge) */ + { "_SDB_SERVER_CONNECT", &ECORE_X_ATOM_SDB_SERVER_CONNECT }, + { "_SDB_SERVER_DISCONNECT", &ECORE_X_ATOM_SDB_SERVER_DISCONNECT } +}; + diff --git a/src/lib/ecore_x/xcb/Makefile.am b/src/lib/ecore_x/xcb/Makefile.am index 39dde65..366ebfd 100644 --- a/src/lib/ecore_x/xcb/Makefile.am +++ b/src/lib/ecore_x/xcb/Makefile.am @@ -1,81 +1,98 @@ -MAINTAINERCLEANFILES = Makefile.in +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_CFLAGS@ \ --I$(top_srcdir)/src/lib/ecore \ --I$(top_srcdir)/src/lib/ecore_txt \ --I$(top_srcdir)/src/lib/ecore_x \ --I$(top_builddir)/src/lib/ecore \ --I$(top_builddir)/src/lib/ecore_txt \ --I$(top_builddir)/src/lib/ecore_x + @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 +noinst_LTLIBRARIES = libecore_x_xcb.la -libecore_x_xcb_la_SOURCES = \ -ecore_xcb_atom.c \ -ecore_xcb_cursor.c \ -ecore_xcb_damage.c \ -ecore_xcb_composite.c \ -ecore_xcb_dnd.c \ -ecore_xcb_dpms.c \ -ecore_xcb_drawable.c \ -ecore_xcb_e.c \ -ecore_xcb_events.c \ -ecore_xcb_fixes.c \ -ecore_xcb_gc.c \ -ecore_xcb_icccm.c \ -ecore_xcb_mwm.c \ -ecore_xcb_netwm.c \ -ecore_xcb_pixmap.c \ -ecore_xcb_randr.c \ -ecore_xcb_reply.c \ -ecore_xcb_screensaver.c \ -ecore_xcb_selection.c \ -ecore_xcb_shape.c \ -ecore_xcb_sync.c \ -ecore_xcb_window.c \ -ecore_xcb_window_prop.c \ -ecore_xcb_window_shadow.c \ -ecore_xcb_xinerama.c \ -ecore_xcb.c +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_LIBS@ \ -$(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_txt/libecore_txt.la - -libecore_x_xcb_la_LDFLAGS = -version-info @version_info@ - -libecore_x_xcb_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_txt/libecore_txt.la + @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 diff --git a/src/lib/ecore_x/xcb/ecore_xcb.c b/src/lib/ecore_x/xcb/ecore_xcb.c index 9ccf5f7..0ca779e 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb.c +++ b/src/lib/ecore_x/xcb/ecore_xcb.c @@ -1,137 +1,30 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include - -#include "Ecore.h" #include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" - -static int _ecore_xcb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_xcb_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_xcb_key_mask_get(xcb_keysym_t sym); -static void *_ecore_xcb_event_filter_start(void *data); -static int _ecore_xcb_event_filter_filter(void *data, void *loop_data,int type, void *event); -static void _ecore_xcb_event_filter_end(void *data, void *loop_data); - -static Ecore_Fd_Handler *_ecore_xcb_fd_handler_handle = NULL; -static Ecore_Event_Filter *_ecore_xcb_filter_handler = NULL; - -#ifdef ECORE_XCB_DAMAGE -static int _ecore_xcb_event_damage_id = 0; -#endif /* ECORE_XCB_DAMAGE */ -#ifdef ECORE_XCB_RANDR -static int _ecore_xcb_event_randr_id = 0; -#endif /* ECORE_XCB_RANDR */ -#ifdef ECORE_XCB_SCREENSAVER -static int _ecore_xcb_event_screensaver_id = 0; -#endif /* ECORE_XCB_SCREENSAVER */ -#ifdef ECORE_XCB_SHAPE -static int _ecore_xcb_event_shape_id = 0; -#endif /* ECORE_XCB_SHAPE */ -#ifdef ECORE_XCB_SYNC -static int _ecore_xcb_event_sync_id = 0; -#endif /* ECORE_XCB_SYNC */ -#ifdef ECORE_XCB_FIXES -static int _ecore_xcb_event_fixes_selection_id = 0; -#endif /* ECORE_XCB_FIXES */ - -static int _ecore_xcb_event_handlers_num = 0; -static void (**_ecore_xcb_event_handlers) (xcb_generic_event_t * event) = NULL; -static xcb_generic_event_t *_ecore_xcb_event_buffered = NULL; +#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; -double _ecore_xcb_double_click_time = 0.25; -Ecore_X_Time _ecore_xcb_event_last_time = XCB_NONE; -Ecore_X_Window _ecore_xcb_event_last_window = XCB_NONE; -int16_t _ecore_xcb_event_last_root_x = 0; -int16_t _ecore_xcb_event_last_root_y = 0; -int _ecore_xcb_xcursor = 0; - -Ecore_X_Window _ecore_xcb_private_window = 0; - -/* FIXME - These are duplicates after making ecore atoms public */ - -Ecore_X_Atom _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM]; - - -EAPI int ECORE_X_EVENT_KEY_DOWN = 0; -EAPI int ECORE_X_EVENT_KEY_UP = 0; -EAPI int ECORE_X_EVENT_MOUSE_BUTTON_DOWN = 0; -EAPI int ECORE_X_EVENT_MOUSE_BUTTON_UP = 0; -EAPI int ECORE_X_EVENT_MOUSE_MOVE = 0; -EAPI int ECORE_X_EVENT_MOUSE_IN = 0; -EAPI int ECORE_X_EVENT_MOUSE_OUT = 0; -EAPI int ECORE_X_EVENT_MOUSE_WHEEL = 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_SELECTION_CLEAR = 0; -EAPI int ECORE_X_EVENT_SELECTION_REQUEST = 0; -EAPI int ECORE_X_EVENT_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_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_WINDOW_DELETE_REQUEST = 0; -/* -EAPI int ECORE_X_EVENT_WINDOW_PROP_TITLE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_DESKTOP_CHANGE = 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_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_LOCK_SCROLL = 0; -EAPI int ECORE_X_LOCK_NUM = 0; -EAPI int ECORE_X_LOCK_CAPS = 0; +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_Xcb_Init_Group X Library Init and Shutdown Functions + * @defgroup Ecore_X_Init_Group X Library Init and Shutdown Functions * * Functions that start and shut down the Ecore X Library. */ @@ -143,494 +36,251 @@ EAPI int ECORE_X_LOCK_CAPS = 0; * assumed. * @return The number of times the library has been initialized without * being shut down. 0 is returned if an error occurs. - * @ingroup Ecore_Xcb_Init_Group + * @ingroup Ecore_X_Init_Group */ EAPI int ecore_x_init(const char *name) { - xcb_screen_iterator_t iter; - int screen; - uint32_t max_request_length; - const xcb_query_extension_reply_t *reply_big_requests; -#ifdef ECORE_XCB_DAMAGE - const xcb_query_extension_reply_t *reply_damage; -#endif /* ECORE_XCB_DAMAGE */ -#ifdef ECORE_XCB_COMPOSITE - const xcb_query_extension_reply_t *reply_composite; -#endif /* ECORE_XCB_COMPOSITE */ -#ifdef ECORE_XCB_DPMS - const xcb_query_extension_reply_t *reply_dpms; -#endif /* ECORE_XCB_DPMS */ -#ifdef ECORE_XCB_RANDR - const xcb_query_extension_reply_t *reply_randr; -#endif /* ECORE_XCB_RANDR */ -#ifdef ECORE_XCB_SCREENSAVER - const xcb_query_extension_reply_t *reply_screensaver; -#endif /* ECORE_XCB_SCREENSAVER */ -#ifdef ECORE_XCB_SHAPE - const xcb_query_extension_reply_t *reply_shape; -#endif /* ECORE_XCB_SHAPE */ -#ifdef ECORE_XCB_SYNC - xcb_sync_initialize_cookie_t cookie_sync_init; - xcb_sync_initialize_reply_t *reply_sync_init; - const xcb_query_extension_reply_t *reply_sync; -#endif /* ECORE_XCB_SYNC */ -#ifdef ECORE_XCB_FIXES - const xcb_query_extension_reply_t *reply_xfixes; -#endif /* ECORE_XCB_FIXES */ -#ifdef ECORE_XCB_XINERAMA - const xcb_query_extension_reply_t *reply_xinerama; -#endif /* ECORE_XCB_XINERAMA */ -#ifdef ECORE_XCB_XPRINT - const xcb_query_extension_reply_t *reply_xprint; -#endif /* ECORE_XCB_XPRINT */ - - xcb_intern_atom_cookie_t atom_cookies[ECORE_X_ATOMS_COUNT]; - - if (_ecore_xcb_init_count > 0) + 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()) { - _ecore_xcb_init_count++; - return _ecore_xcb_init_count; + /* unregister log domain */ + eina_log_domain_unregister(_ecore_xcb_log_dom); + _ecore_xcb_log_dom = -1; + eina_shutdown(); + return --_ecore_xcb_init_count; } - _ecore_xcb_conn = xcb_connect(name, &screen); - if (!_ecore_xcb_conn) return 0; - /* FIXME: no error code right now */ - /* _ecore_xcb_error_handler_init(); */ + /* 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; + } - /********************/ - /* First round trip */ - /********************/ + /* NB: XLib has XInitThreads */ - /* - * Non blocking stuff: + /* check for env var which says we are not going to use GL @ all * - * 1. We request the atoms - * 2. We Prefetch the extension data + * 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; + } - /* We request the atoms (non blocking) */ - _ecore_x_atom_init(atom_cookies); - - /* We prefetch all the extension data (non blocking) */ + 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; + } - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_big_requests_id); + _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 -#ifdef ECORE_XCB_DAMAGE - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_damage_id); -#endif /* ECORE_XCB_DAMAGE */ + 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); + } + } -#ifdef ECORE_XCB_COMPOSITE - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_composite_id); -#endif /* ECORE_XCB_COMPOSITE */ + 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; + } -#ifdef ECORE_XCB_DPMS - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_dpms_id); -#endif /* ECORE_XCB_DPMS */ + /* grab the default screen */ + _ecore_xcb_screen = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).data; -#ifdef ECORE_XCB_RANDR - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_randr_id); -#endif /* ECORE_XCB_RANDR */ + /* 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 */ -#ifdef ECORE_XCB_SCREENSAVER - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_screensaver_id); -#endif /* ECORE_XCB_SCREENSAVER */ + /* prefetch extension data */ + _ecore_xcb_extensions_init(); -#ifdef ECORE_XCB_SHAPE - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shape_id); -#endif /* ECORE_XCB_SHAPE */ + /* finalize extensions */ + _ecore_xcb_extensions_finalize(); -#ifdef ECORE_XCB_SYNC - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_sync_id); - cookie_sync_init = xcb_sync_initialize_unchecked(_ecore_xcb_conn, - XCB_SYNC_MAJOR_VERSION, - XCB_SYNC_MINOR_VERSION); -#endif /* ECORE_XCB_SYNC */ + /* 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); -#ifdef ECORE_XCB_FIXES - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xfixes_id); -#endif /* ECORE_XCB_FIXES */ + /* setup xcb events */ + _ecore_xcb_events_init(); -#ifdef ECORE_XCB_XINERAMA - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); -#endif /* ECORE_XCB_XINERAMA */ + /* setup xcb keymasks */ + _ecore_xcb_keymap_init(); -#ifdef ECORE_XCB_XPRINT - xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_x_print_id); -#endif /* ECORE_XCB_XPRINT */ + /* finalize xcb keymasks */ + _ecore_xcb_keymap_finalize(); - /* We init some components (not related to XCB) */ - _ecore_x_reply_init(); - _ecore_x_dnd_init(); - ecore_x_netwm_init(); - _ecore_x_selection_init(); - - /* There is no LASTEvent constant in XCB */ - /* LASTevent is equal to 35 */ - _ecore_xcb_event_handlers_num = 35; - - /* We get the default screen */ - iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); - for (; iter.rem; --screen, xcb_screen_next (&iter)) - if (screen == 0) - { - _ecore_xcb_screen = iter.data; - break; - } - - /* - * Blocking stuff: - * - * 1. We get the atoms - * 2. We ask for the extension data - * - */ + /* 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); - /* We get the atoms (blocking) */ - _ecore_x_atom_init_finalize(atom_cookies); - - /* We then ask for the extension data (blocking) */ - reply_big_requests = xcb_get_extension_data(_ecore_xcb_conn, &xcb_big_requests_id); - -#ifdef ECORE_XCB_DAMAGE - reply_damage = xcb_get_extension_data(_ecore_xcb_conn, &xcb_damage_id); - if (reply_damage) - _ecore_xcb_event_damage_id = reply_damage->first_event + XCB_DAMAGE_NOTIFY; - if (_ecore_xcb_event_damage_id >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_damage_id + 1; -#endif /* ECORE_XCB_DAMAGE */ - -#ifdef ECORE_XCB_COMPOSITE - reply_composite = xcb_get_extension_data(_ecore_xcb_conn, &xcb_composite_id); -#endif /* ECORE_XCB_COMPOSITE */ - -#ifdef ECORE_XCB_DPMS - reply_dpms = xcb_get_extension_data(_ecore_xcb_conn, &xcb_dpms_id); -#endif /* ECORE_XCB_DPMS */ - -#ifdef ECORE_XCB_RANDR - reply_randr = xcb_get_extension_data(_ecore_xcb_conn, &xcb_randr_id); - if (reply_randr) - _ecore_xcb_event_randr_id = reply_randr->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY; - if (_ecore_xcb_event_randr_id >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_randr_id + 1; -#endif /* ECORE_XCB_RANDR */ - -#ifdef ECORE_XCB_SCREENSAVER - reply_screensaver = xcb_get_extension_data(_ecore_xcb_conn, &xcb_screensaver_id); - if (reply_screensaver) - _ecore_xcb_event_screensaver_id = reply_screensaver->first_event + XCB_SCREENSAVER_NOTIFY; - if (_ecore_xcb_event_screensaver_id >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_screensaver_id + 1; -#endif /* ECORE_XCB_SCREENSAVER */ - -#ifdef ECORE_XCB_SHAPE - reply_shape = xcb_get_extension_data(_ecore_xcb_conn, &xcb_shape_id); - if (reply_shape) - _ecore_xcb_event_shape_id = reply_shape->first_event + XCB_SHAPE_NOTIFY; - if (_ecore_xcb_event_shape_id >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_shape_id + 1; -#endif /* ECORE_XCB_SHAPE */ - -#ifdef ECORE_XCB_SYNC - reply_sync = xcb_get_extension_data(_ecore_xcb_conn, &xcb_sync_id); - if (reply_sync) - { - _ecore_xcb_event_sync_id = reply_sync->first_event; - reply_sync_init = xcb_sync_initialize_reply(_ecore_xcb_conn, - cookie_sync_init, NULL); - if (!reply_sync_init) - _ecore_xcb_event_sync_id = 0; - else - free(reply_sync_init); - } - if (_ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY + 1; -#endif /* ECORE_XCB_SYNC */ - -#ifdef ECORE_XCB_FIXES - reply_xfixes = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xfixes_id); - if (reply_xfixes) - _ecore_xcb_event_fixes_selection_id = reply_xfixes->first_event + XCB_XFIXES_SELECTION_NOTIFY; - if (_ecore_xcb_event_fixes_selection_id >= _ecore_xcb_event_handlers_num) - _ecore_xcb_event_handlers_num = _ecore_xcb_event_fixes_selection_id + 1; -#endif /* ECORE_XCB_FIXES */ - -#ifdef ECORE_XCB_XINERAMA - reply_xinerama = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); -#endif /* ECORE_XCB_XINERAMA */ - -#ifdef ECORE_XCB_XPRINT - reply_xprint = xcb_get_extension_data(_ecore_xcb_conn, &xcb_x_print_id); -#endif /* ECORE_XCB_XPRINT */ - - /*********************/ - /* Second round trip */ - /*********************/ - - /* We ask for the QueryVersion request of the extensions */ - _ecore_x_damage_init(reply_damage); - _ecore_x_composite_init(reply_composite); - _ecore_x_dpms_init(reply_dpms); - _ecore_x_randr_init(reply_randr); - _ecore_x_shape_init(reply_shape); - _ecore_x_sync_init(reply_sync); - _ecore_x_xfixes_init(reply_xfixes); - _ecore_x_xinerama_init(reply_xinerama); - - /* we enable the Big Request extension if present */ - max_request_length = xcb_get_maximum_request_length(_ecore_xcb_conn); - - _ecore_xcb_event_handlers = calloc(_ecore_xcb_event_handlers_num, sizeof(void *)); - if (!_ecore_xcb_event_handlers) - { - /* We get the replies of the QueryVersion request because we leave */ - _ecore_x_damage_init_finalize(); - _ecore_x_composite_init_finalize(); - _ecore_x_dpms_init_finalize(); - _ecore_x_randr_init_finalize(); - _ecore_x_shape_init_finalize(); - _ecore_x_sync_init_finalize(); - _ecore_x_xfixes_init_finalize(); - _ecore_x_xinerama_init_finalize(); - - xcb_disconnect(_ecore_xcb_conn); - _ecore_xcb_fd_handler_handle = NULL; - _ecore_xcb_conn = NULL; - return 0; - } + if (!_ecore_xcb_fd_handler) + return _ecore_xcb_shutdown(EINA_TRUE); -#ifdef ECORE_XCB_CURSOR - _ecore_xcb_xcursor = XcursorSupportsARGB(_ecore_xcb_conn); -#endif /* ECORE_XCB_CURSOR */ - - _ecore_xcb_event_handlers[XCB_KEY_PRESS] = _ecore_x_event_handle_key_press; - _ecore_xcb_event_handlers[XCB_KEY_RELEASE] = _ecore_x_event_handle_key_release; - _ecore_xcb_event_handlers[XCB_BUTTON_PRESS] = _ecore_x_event_handle_button_press; - _ecore_xcb_event_handlers[XCB_BUTTON_RELEASE] = _ecore_x_event_handle_button_release; - _ecore_xcb_event_handlers[XCB_MOTION_NOTIFY] = _ecore_x_event_handle_motion_notify; - _ecore_xcb_event_handlers[XCB_ENTER_NOTIFY] = _ecore_x_event_handle_enter_notify; - _ecore_xcb_event_handlers[XCB_LEAVE_NOTIFY] = _ecore_x_event_handle_leave_notify; - _ecore_xcb_event_handlers[XCB_FOCUS_IN] = _ecore_x_event_handle_focus_in; - _ecore_xcb_event_handlers[XCB_FOCUS_OUT] = _ecore_x_event_handle_focus_out; - _ecore_xcb_event_handlers[XCB_KEYMAP_NOTIFY] = _ecore_x_event_handle_keymap_notify; - _ecore_xcb_event_handlers[XCB_EXPOSE] = _ecore_x_event_handle_expose; - _ecore_xcb_event_handlers[XCB_GRAPHICS_EXPOSURE] = _ecore_x_event_handle_graphics_expose; - _ecore_xcb_event_handlers[XCB_VISIBILITY_NOTIFY] = _ecore_x_event_handle_visibility_notify; - _ecore_xcb_event_handlers[XCB_CREATE_NOTIFY] = _ecore_x_event_handle_create_notify; - _ecore_xcb_event_handlers[XCB_DESTROY_NOTIFY] = _ecore_x_event_handle_destroy_notify; - _ecore_xcb_event_handlers[XCB_UNMAP_NOTIFY] = _ecore_x_event_handle_unmap_notify; - _ecore_xcb_event_handlers[XCB_MAP_NOTIFY] = _ecore_x_event_handle_map_notify; - _ecore_xcb_event_handlers[XCB_MAP_REQUEST] = _ecore_x_event_handle_map_request; - _ecore_xcb_event_handlers[XCB_REPARENT_NOTIFY] = _ecore_x_event_handle_reparent_notify; - _ecore_xcb_event_handlers[XCB_CONFIGURE_NOTIFY] = _ecore_x_event_handle_configure_notify; - _ecore_xcb_event_handlers[XCB_CONFIGURE_REQUEST] = _ecore_x_event_handle_configure_request; - _ecore_xcb_event_handlers[XCB_GRAVITY_NOTIFY] = _ecore_x_event_handle_gravity_notify; - _ecore_xcb_event_handlers[XCB_RESIZE_REQUEST] = _ecore_x_event_handle_resize_request; - _ecore_xcb_event_handlers[XCB_CIRCULATE_NOTIFY] = _ecore_x_event_handle_circulate_notify; - _ecore_xcb_event_handlers[XCB_CIRCULATE_REQUEST] = _ecore_x_event_handle_circulate_request; - _ecore_xcb_event_handlers[XCB_PROPERTY_NOTIFY] = _ecore_x_event_handle_property_notify; - _ecore_xcb_event_handlers[XCB_SELECTION_CLEAR] = _ecore_x_event_handle_selection_clear; - _ecore_xcb_event_handlers[XCB_SELECTION_REQUEST] = _ecore_x_event_handle_selection_request; - _ecore_xcb_event_handlers[XCB_SELECTION_NOTIFY] = _ecore_x_event_handle_selection_notify; - _ecore_xcb_event_handlers[XCB_COLORMAP_NOTIFY] = _ecore_x_event_handle_colormap_notify; - _ecore_xcb_event_handlers[XCB_CLIENT_MESSAGE] = _ecore_x_event_handle_client_message; - _ecore_xcb_event_handlers[XCB_MAPPING_NOTIFY] = _ecore_x_event_handle_mapping_notify; -#ifdef ECORE_XCB_DAMAGE - if (_ecore_xcb_event_damage_id) - _ecore_xcb_event_handlers[_ecore_xcb_event_damage_id] = _ecore_x_event_handle_damage_notify; -#endif /* ECORE_XCB_DAMAGE */ -#ifdef ECORE_XCB_RANDR - if (_ecore_xcb_event_randr_id) - _ecore_xcb_event_handlers[_ecore_xcb_event_randr_id] = _ecore_x_event_handle_randr_change; -#endif /* ECORE_XCB_RANDR */ -#ifdef ECORE_XCB_SCREENSAVER - if (_ecore_xcb_event_screensaver_id) - _ecore_xcb_event_handlers[_ecore_xcb_event_screensaver_id] = _ecore_x_event_handle_screensaver_notify; -#endif /* ECORE_XCB_SCREENSAVER */ -#ifdef ECORE_XCB_SHAPE - if (_ecore_xcb_event_shape_id) - _ecore_xcb_event_handlers[_ecore_xcb_event_shape_id] = _ecore_x_event_handle_shape_change; -#endif /* ECORE_XCB_SHAPE */ -#ifdef ECORE_XCB_SYNC - if (_ecore_xcb_event_sync_id) - { - _ecore_xcb_event_handlers[_ecore_xcb_event_sync_id + XCB_SYNC_COUNTER_NOTIFY] = - _ecore_x_event_handle_sync_counter; - _ecore_xcb_event_handlers[_ecore_xcb_event_sync_id + XCB_SYNC_ALARM_NOTIFY] = - _ecore_x_event_handle_sync_alarm; - } -#endif /* ECORE_XCB_SYNC */ -#ifdef ECORE_XCB_FIXES - if (_ecore_xcb_event_fixes_selection_id) - _ecore_xcb_event_handlers[_ecore_xcb_event_fixes_selection_id] = _ecore_x_event_handle_fixes_selection_notify; -#endif /* ECORE_XCB_FIXES */ + /* prefetch atoms */ + _ecore_xcb_atoms_init(); - if (!ECORE_X_EVENT_KEY_DOWN) - { - ECORE_X_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_X_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_MOVE = 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_MOUSE_WHEEL = 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_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_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_DAMAGE_NOTIFY = ecore_event_type_new(); - - ECORE_X_EVENT_WINDOW_DELETE_REQUEST = ecore_event_type_new(); - /* - ECORE_X_EVENT_WINDOW_PROP_TITLE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_DESKTOP_CHANGE = 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(); - } + /* finalize atoms */ + _ecore_xcb_atoms_finalize(); - /* everything has these... unless its like a pda... :) */ - ECORE_X_MODIFIER_SHIFT = _ecore_xcb_key_mask_get(XK_Shift_L); - ECORE_X_MODIFIER_CTRL = _ecore_xcb_key_mask_get(XK_Control_L); - - /* apple's xdarwin has no alt!!!! */ - ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Alt_L); - if (!ECORE_X_MODIFIER_ALT) - ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Meta_L); - if (!ECORE_X_MODIFIER_ALT) - ECORE_X_MODIFIER_ALT = _ecore_xcb_key_mask_get(XK_Super_L); - - /* the windows key... a valid modifier :) */ - ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Super_L); - if (!ECORE_X_MODIFIER_WIN) - ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Mode_switch); - if (!ECORE_X_MODIFIER_WIN) - ECORE_X_MODIFIER_WIN = _ecore_xcb_key_mask_get(XK_Meta_L); - - 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_key_mask_get(XK_Scroll_Lock); - ECORE_X_LOCK_NUM = _ecore_xcb_key_mask_get(XK_Num_Lock); - ECORE_X_LOCK_CAPS = _ecore_xcb_key_mask_get(XK_Caps_Lock); - - _ecore_xcb_fd_handler_handle = - ecore_main_fd_handler_add(xcb_get_file_descriptor(_ecore_xcb_conn), - ECORE_FD_READ, - _ecore_xcb_fd_handler, _ecore_xcb_conn, - _ecore_xcb_fd_handler_buf, _ecore_xcb_conn); - if (!_ecore_xcb_fd_handler_handle) - { - /* We get the replies of the QueryVersion request because we leave */ - _ecore_x_damage_init_finalize(); - _ecore_x_composite_init_finalize(); - _ecore_x_dpms_init_finalize(); - _ecore_x_randr_init_finalize(); - _ecore_x_shape_init_finalize(); - _ecore_x_sync_init_finalize(); - _ecore_x_xfixes_init_finalize(); - _ecore_x_xinerama_init_finalize(); - - xcb_disconnect(_ecore_xcb_conn); - free(_ecore_xcb_event_handlers); - _ecore_xcb_fd_handler_handle = NULL; - _ecore_xcb_conn = NULL; - _ecore_xcb_event_handlers = NULL; - return 0; - } - _ecore_xcb_filter_handler = ecore_event_filter_add(_ecore_xcb_event_filter_start, _ecore_xcb_event_filter_filter, _ecore_xcb_event_filter_end, NULL); + /* icccm_init: dummy function */ + ecore_x_icccm_init(); - /* This is just to be anal about naming conventions */ + /* setup netwm */ + ecore_x_netwm_init(); - _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_DELETE_REQUEST] = ECORE_X_ATOM_WM_DELETE_WINDOW; - _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_TAKE_FOCUS] = ECORE_X_ATOM_WM_TAKE_FOCUS; - _ecore_xcb_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_PING] = ECORE_X_ATOM_NET_WM_PING; - _ecore_xcb_atoms_wm_protocols[ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST; + /* old e hints init: dummy function */ + ecore_x_e_init(); - _ecore_xcb_init_count++; + _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; - _ecore_xcb_private_window = ecore_x_window_override_new(0, -77, -777, 123, 456); + /* setup selection */ + _ecore_xcb_selection_init(); - /* We finally get the replies of the QueryVersion request */ - _ecore_x_damage_init_finalize(); - _ecore_x_composite_init_finalize(); - _ecore_x_dpms_init_finalize(); - _ecore_x_randr_init_finalize(); - _ecore_x_shape_init_finalize(); - _ecore_x_sync_init_finalize(); - _ecore_x_xfixes_init_finalize(); - _ecore_x_xinerama_init_finalize(); + /* setup dnd */ + _ecore_xcb_dnd_init(); - return _ecore_xcb_init_count; -} + _ecore_xcb_idle_enterer = + ecore_idle_enterer_add(_ecore_xcb_idle_enter, NULL); -static int -_ecore_x_shutdown(int close_display) -{ - _ecore_xcb_init_count--; - if (_ecore_xcb_init_count > 0) return _ecore_xcb_init_count; - if (!_ecore_xcb_conn) return _ecore_xcb_init_count; - if (close_display) - xcb_disconnect(_ecore_xcb_conn); - else - close(xcb_get_file_descriptor(_ecore_xcb_conn)); - free(_ecore_xcb_event_handlers); - ecore_main_fd_handler_del(_ecore_xcb_fd_handler_handle); - ecore_event_filter_del(_ecore_xcb_filter_handler); - _ecore_xcb_fd_handler_handle = NULL; - _ecore_xcb_filter_handler = NULL; - _ecore_xcb_conn = NULL; - _ecore_xcb_event_handlers = NULL; - _ecore_x_selection_shutdown(); - _ecore_x_dnd_shutdown(); - ecore_x_netwm_shutdown(); - _ecore_x_reply_shutdown(); - if (_ecore_xcb_init_count < 0) _ecore_xcb_init_count = 0; return _ecore_xcb_init_count; } @@ -642,1200 +292,1292 @@ _ecore_x_shutdown(int close_display) * * @return The number of times the library has been initialized without * being shut down. - * @ingroup Ecore_Xcb_Init_Group + * @ingroup Ecore_X_Init_Group */ EAPI int ecore_x_shutdown(void) { - return _ecore_x_shutdown(1); + return _ecore_xcb_shutdown(EINA_TRUE); } /** * Shuts down the Ecore X library. * - * As ecore_xcb_shutdown, except do not close Display, only connection. + * As ecore_x_shutdown, except do not close Display, only connection. * - * @ingroup Ecore_Xcb_Init_Group + * @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_x_shutdown(0); + return _ecore_xcb_shutdown(EINA_FALSE); } /** - * @defgroup Ecore_Xcb_Display_Attr_Group X Display Attributes + * @defgroup Ecore_X_Flush_Group X Synchronization Functions * - * Functions that set and retrieve X display attributes. + * Functions that ensure that all commands that have been issued by the + * Ecore X library have been sent to the server. */ -EAPI Ecore_X_Display * -ecore_x_display_get(void) -{ - return NULL; -} - /** - * Retrieves the Ecore_X_Connection handle used for the current X connection. - * @return The current X connection. - * @ingroup Ecore_Xcb_Display_Attr_Group + * Sends all X commands in the X Display buffer. + * @ingroup Ecore_X_Flush_Group */ -EAPI Ecore_X_Connection * -ecore_x_connection_get(void) +EAPI void +ecore_x_flush(void) { - return (Ecore_X_Connection *)_ecore_xcb_conn; -} +// LOGFN(__FILE__, __LINE__, __FUNCTION__); -/** - * Retrieves the X display file descriptor. - * @return The current X display file descriptor. - * @ingroup Ecore_Xcb_Display_Attr_Group - */ -EAPI int -ecore_x_fd_get(void) -{ - return xcb_get_file_descriptor(_ecore_xcb_conn); + 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_Xcb_Display_Attr_Group + * @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; } -/** - * 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_Xcb_Display_Attr_Group - */ -EAPI void -ecore_x_double_click_time_set(double t) +EAPI Ecore_X_Connection * +ecore_x_connection_get(void) { - if (t < 0.0) t = 0.0; - _ecore_xcb_double_click_time = t; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + return (Ecore_X_Connection *)_ecore_xcb_conn; } /** - * Retrieves the double and triple click flag timeout. - * - * See @ref ecore_xcb_double_click_time_set for more information. - * - * @return The timeout for double clicks in seconds. - * @ingroup Ecore_Xcb_Display_Attr_Group + * Return the last event time */ -EAPI double -ecore_x_double_click_time_get(void) +EAPI Ecore_X_Time +ecore_x_current_time_get(void) { - return _ecore_xcb_double_click_time; + return _ecore_xcb_events_last_time_get(); } /** - * @defgroup Ecore_Xcb_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. + * 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)); +} -/** - * Sends all X commands in the X Display buffer. - * @ingroup Ecore_Xcb_Flush_Group - */ EAPI void -ecore_x_flush(void) +ecore_x_grab(void) { - xcb_flush(_ecore_xcb_conn); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + CHECK_XCB_CONN; + _ecore_xcb_grab_count++; + if (_ecore_xcb_grab_count == 1) + xcb_grab_server(_ecore_xcb_conn); } -/** - * Flushes the command buffer and waits until all requests have been - * processed by the server. - * @ingroup Ecore_Xcb_Flush_Group - */ EAPI void -ecore_x_sync(void) +ecore_x_ungrab(void) { - free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), NULL)); + 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); } /** - * Kill all clients with subwindows under a given window. + * Send client message with given type and format 32. * - * 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 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 * - * @param root The window whose children will be killed. + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. */ -EAPI void -ecore_x_killall(Ecore_X_Window root) +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) { - int screens; - int i; + xcb_client_message_event_t ev; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; - xcb_grab_server(_ecore_xcb_conn); - screens = xcb_setup_roots_iterator (xcb_get_setup (_ecore_xcb_conn)).rem; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* Tranverse 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; + memset(&ev, 0, sizeof(xcb_client_message_event_t)); - cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, root); - reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); - if (reply) - { - xcb_window_iterator_t iter; + 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; - iter = xcb_query_tree_children_iterator(reply); - for (; iter.rem; xcb_window_next(&iter)) - xcb_kill_client(_ecore_xcb_conn, *iter.data); - free(reply); - } + 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; } - xcb_ungrab_server(_ecore_xcb_conn); - free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), NULL)); + return EINA_TRUE; } /** - * Kill a specific client + * Send client message with given type and format 8. * - * You can kill a specific client woning window @p window + * @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. * - * @param window Window of the client to be killed + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. */ -EAPI void -ecore_x_kill(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, + const void *data, int len) { - xcb_kill_client(_ecore_xcb_conn, window); -} + xcb_client_message_event_t ev; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; -/** - * Return the last event time - */ -EAPI Ecore_X_Time -ecore_x_current_time_get(void) -{ - return _ecore_xcb_event_last_time; -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -static void -handle_event(xcb_generic_event_t *ev) -{ - uint8_t response_type = ev->response_type & ~0x80; + 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); - if (response_type < _ecore_xcb_event_handlers_num) + 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) { - if (_ecore_xcb_event_handlers[response_type]) - _ecore_xcb_event_handlers[response_type] (ev); + 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; } -static int -_ecore_xcb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +EAPI Eina_Bool +ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b) { - xcb_connection_t *c; - xcb_generic_event_t *ev; + 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; - c = (xcb_connection_t *)data; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/* printf ("nbr events: %d\n", _ecore_xcb_event_handlers_num); */ + 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; - /* We check if _ecore_xcb_event_buffered is NULL or not */ - if (_ecore_xcb_event_buffered) - handle_event(_ecore_xcb_event_buffered); + 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); - while ((ev = xcb_poll_for_event(c))) - handle_event(ev); + 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 1; + return EINA_TRUE; } -static int -_ecore_xcb_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +EAPI Eina_Bool +ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b) { - xcb_connection_t *c; + 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; - c = (xcb_connection_t *)data; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - _ecore_xcb_event_buffered = xcb_poll_for_event(c); - if (!_ecore_xcb_event_buffered) - return 0; - - return 1; -} + 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; -/* FIXME: possible roundtrip */ -/* FIXME: fix xcb_keysyms. It's ugly !! (reply in xcb_key_symbols_get_keysym) */ -static int -_ecore_xcb_key_mask_get(xcb_keysym_t sym) -{ - xcb_keycode_iterator_t iter; - xcb_get_modifier_mapping_cookie_t cookie; - xcb_get_modifier_mapping_reply_t *reply; - xcb_key_symbols_t *symbols; - xcb_keysym_t sym2; - int i, j; - 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 - }; - - cookie = xcb_get_modifier_mapping_unchecked(_ecore_xcb_conn); - symbols = xcb_key_symbols_alloc(_ecore_xcb_conn); - - reply = xcb_get_modifier_mapping_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - { - xcb_key_symbols_free(symbols); + memset(&ev, 0, sizeof(xcb_button_release_event_t)); - return 0; - } + 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); - iter = xcb_get_modifier_mapping_keycodes_iterator(reply); + vcookie = xcb_send_event(_ecore_xcb_conn, 1, win, + XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev); - for (i = 0; iter.rem; xcb_keycode_next(&iter), i++) + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) { - for (j = 0; j < 8; j++) - { - sym2 = xcb_key_symbols_get_keysym(symbols, *iter.data, j); - if (sym2 != 0) break; - } - if (sym2 == sym) - { - int mask; - - mask = masks[i]; - free(reply); - xcb_key_symbols_free(symbols); - return mask; - } + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; } - free(reply); - xcb_key_symbols_free(symbols); - - return 0; + return EINA_TRUE; } -typedef struct _Ecore_X_Filter_Data Ecore_X_Filter_Data; - -struct _Ecore_X_Filter_Data +EAPI Eina_Bool +ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y) { - int last_event_type; -}; + 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; -static void * -_ecore_xcb_event_filter_start(void *data __UNUSED__) -{ - Ecore_X_Filter_Data *filter_data; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - filter_data = calloc(1, sizeof(Ecore_X_Filter_Data)); - return filter_data; -} + 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; -static int -_ecore_xcb_event_filter_filter(void *data __UNUSED__, void *loop_data,int type, void *event __UNUSED__) -{ - Ecore_X_Filter_Data *filter_data; + 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); - filter_data = loop_data; - if (!filter_data) return 1; - if (type == ECORE_X_EVENT_MOUSE_MOVE) + err = xcb_request_check(_ecore_xcb_conn, vcookie); + if (err) { - if ((filter_data->last_event_type) == ECORE_X_EVENT_MOUSE_MOVE) - { - filter_data->last_event_type = type; - return 0; - } + _ecore_xcb_error_handle(err); + free(err); + return EINA_FALSE; } - filter_data->last_event_type = type; - return 1; + + return EINA_TRUE; } -static void -_ecore_xcb_event_filter_end(void *data __UNUSED__, void *loop_data) +EAPI Eina_Bool +ecore_x_mouse_in_send(Ecore_X_Window win, int x, int y) { - Ecore_X_Filter_Data *filter_data; - - filter_data = loop_data; - if (filter_data) free(filter_data); -} - - + 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; +} -/*****************************************************************************/ -/*****************************************************************************/ -/*****************************************************************************/ -/* FIXME: these funcs need categorising */ -/*****************************************************************************/ +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; -/** - * 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; - const xcb_setup_t *setup; - uint8_t i; - uint8_t num; - Ecore_X_Window *roots; -/* #ifdef ECORE_XCBXPRINT */ -/* int xp_base, xp_err_base; */ -/* #endif /\* ECORE_XCBXPRINT *\/ */ - - if (!num_ret) return NULL; - *num_ret = 0; - - /* FIXME: todo... */ -/* #ifdef ECORE_XCBXPRINT */ -/* num = ScreenCount(_ecore_xcb_conn); */ -/* if (ecore_xcb_xprint_query()) */ -/* { */ -/* Screen **ps = NULL; */ -/* int psnum = 0; */ - -/* ps = XpQueryScreens(_ecore_xcb_conn, &psnum); */ -/* if (ps) */ -/* { */ -/* int overlap, j; */ - -/* overlap = 0; */ -/* for (i = 0; i < num; i++) */ -/* { */ -/* for (j = 0; j < psnum; j++) */ -/* { */ -/* if (ScreenOfDisplay(_ecore_xcb_conn, i) == ps[j]) */ -/* overlap++; */ -/* } */ -/* } */ -/* roots = malloc((num - overlap) * sizeof(Ecore_X_Window)); */ -/* 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_xcb_conn, i) == ps[j]) */ -/* { */ -/* is_print = 1; */ -/* break; */ -/* } */ -/* } */ -/* if (!is_print) */ -/* { */ -/* roots[k] = RootWindow(_ecore_xcb_conn, i); */ -/* k++; */ -/* } */ -/* } */ -/* *num_ret = k; */ -/* } */ -/* XFree(ps); */ -/* } */ -/* else */ -/* { */ -/* roots = malloc(num * sizeof(Ecore_X_Window)); */ -/* if (!roots) return NULL; */ -/* *num_ret = num; */ -/* for (i = 0; i < num; i++) */ -/* roots[i] = RootWindow(_ecore_xcb_conn, i); */ -/* } */ -/* } */ -/* else */ -/* { */ -/* roots = malloc(num * sizeof(Ecore_X_Window)); */ -/* if (!roots) return NULL; */ -/* *num_ret = num; */ -/* for (i = 0; i < num; i++) */ -/* roots[i] = RootWindow(_ecore_xcb_conn, i); */ -/* } */ -/* #else */ - setup = xcb_get_setup (_ecore_xcb_conn); - iter = xcb_setup_roots_iterator (setup); - num = setup->roots_len; - roots = malloc(num * sizeof(Ecore_X_Window)); - if (!roots) return NULL; - - *num_ret = num; - for (i = 0; iter.rem; xcb_screen_next(&iter), i++) - roots[i] = iter.data->root; -/* #endif /\* ECORE_XCBXPRINT *\/ */ + if (accel_num) *accel_num = reply->acceleration_numerator; + if (accel_denom) *accel_denom = reply->acceleration_denominator; + if (threshold) *threshold = reply->threshold; + free(reply); - return roots; + return EINA_TRUE; } -EAPI Ecore_X_Window -ecore_x_window_root_first_get(void) +EAPI Eina_Bool +ecore_x_pointer_mapping_set(unsigned char *map, int nmap) { - Ecore_X_Window *roots = NULL; - Ecore_X_Window root; - int num; + xcb_set_pointer_mapping_cookie_t cookie; + xcb_set_pointer_mapping_reply_t *reply; + Eina_Bool ret = EINA_FALSE; - roots = ecore_x_window_root_list(&num); - if(!(roots)) return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (num > 0) - root = roots[0]; - else - root = 0; + 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; - free(roots); - return root; -} + if (reply->status == XCB_MAPPING_STATUS_SUCCESS) + ret = EINA_TRUE; -/* FIXME: todo */ - -static void _ecore_x_window_manage_error(void *data); - -static int _ecore_xcb_window_manage_failed = 0; -static void -_ecore_x_window_manage_error(void *data __UNUSED__) -{ -/* if ((ecore_xcb_error_request_get() == X_ChangeWindowAttributes) && */ -/* (ecore_xcb_error_code_get() == BadAccess)) */ -/* _ecore_xcb_window_manage_failed = 1; */ + free(reply); + return ret; } -/* FIXME: round trip */ -EAPI int -ecore_x_window_manage(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_pointer_mapping_get(unsigned char *map, int nmap) { - xcb_get_window_attributes_cookie_t cookie_attr; - xcb_get_input_focus_cookie_t cookie_sync; - xcb_get_window_attributes_reply_t *reply_attr; - xcb_get_input_focus_reply_t *reply_sync; - uint32_t value_list; + xcb_get_pointer_mapping_cookie_t cookie; + xcb_get_pointer_mapping_reply_t *reply; - cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); - cookie_sync = xcb_get_input_focus_unchecked(_ecore_xcb_conn); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply_attr = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_attr, NULL); - if (!reply_attr) + 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) { - reply_sync = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie_sync, NULL); - if (reply_sync) free(reply_sync); - return 0; + free(reply); + return EINA_FALSE; } - reply_sync = xcb_get_input_focus_reply(_ecore_xcb_conn, cookie_sync, NULL); - if (reply_sync) free(reply_sync); - - _ecore_xcb_window_manage_failed = 0; - /* FIXME: no error code yet */ - /* ecore_xcb_error_handler_set(_ecore_xcb_window_manage_error, NULL); */ - - value_list = - XCB_EVENT_MASK_KEY_PRESS | - XCB_EVENT_MASK_KEY_RELEASE | - XCB_EVENT_MASK_ENTER_WINDOW | - XCB_EVENT_MASK_LEAVE_WINDOW | - XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_RESIZE_REDIRECT | - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | - XCB_EVENT_MASK_PROPERTY_CHANGE | - reply_attr->your_event_mask; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_EVENT_MASK, - &value_list); - free(reply_attr); - - cookie_sync = xcb_get_input_focus_unchecked(_ecore_xcb_conn); - if (reply_sync) free(reply_sync); - - /* FIXME: no error code yet */ - /* ecore_xcb_error_handler_set(NULL, NULL); */ - if (_ecore_xcb_window_manage_failed) + if (map) { - _ecore_xcb_window_manage_failed = 0; - return 0; + uint8_t *tmp; + int i = 0; + + tmp = xcb_get_pointer_mapping_map(reply); + for (i = 0; i < nmap; i++) + map[i] = tmp[i]; } - return 1; + 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 int -ecore_x_pointer_control_set(int accel_num, - int accel_denom, - int threshold) +EAPI Eina_Bool +ecore_x_pointer_confine_grab(Ecore_X_Window win) { - xcb_change_pointer_control(_ecore_xcb_conn, - accel_num, accel_denom, threshold, - 1, 1); - return 1; + 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_control_get_prefetch(void) +ecore_x_pointer_ungrab(void) { - xcb_get_pointer_control_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_pointer_control_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); + xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME); } -EAPI void -ecore_x_pointer_control_get_fetch(void) +EAPI Eina_Bool +ecore_x_pointer_warp(Ecore_X_Window win, int x, int y) { - xcb_get_pointer_control_cookie_t cookie; - xcb_get_pointer_control_reply_t *reply; + xcb_void_cookie_t vcookie; + xcb_generic_error_t *err; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_pointer_control_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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; } -EAPI int -ecore_x_pointer_control_get(int *accel_num, - int *accel_denom, - int *threshold) +/** + * 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_get_pointer_control_reply_t *reply; + xcb_void_cookie_t cookie; + xcb_generic_error_t *err; - if (accel_num) *accel_num = 0; - if (accel_denom) *accel_denom = 1; - if (threshold) *threshold = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + CHECK_XCB_CONN; - if (accel_num) *accel_num = reply->acceleration_numerator; - if (accel_denom) *accel_denom = reply->acceleration_denominator; - if (threshold) *threshold = reply->threshold; + // 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 1; + return EINA_TRUE; } -EAPI int -ecore_x_pointer_grab(Ecore_X_Window window) +EAPI void +ecore_x_display_size_get(Ecore_X_Display *dsp __UNUSED__, int *w, int *h) { - xcb_grab_pointer_cookie_t cookie; - xcb_grab_pointer_reply_t *reply; + xcb_screen_t *screen; - cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, window, - 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_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 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - free(reply); - - return 1; + /* 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 int -ecore_x_pointer_confine_grab(Ecore_X_Window window) +EAPI unsigned long +ecore_x_display_black_pixel_get(Ecore_X_Display *dsp __UNUSED__) { - xcb_grab_pointer_cookie_t cookie; - xcb_grab_pointer_reply_t *reply; + xcb_screen_t *screen; - cookie = xcb_grab_pointer_unchecked(_ecore_xcb_conn, 0, window, - 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_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC, - window, XCB_NONE, - XCB_CURRENT_TIME); - reply = xcb_grab_pointer_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - free(reply); + /* 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; - return 1; + 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_ungrab(void) +ecore_x_pointer_last_xy_get(int *x, int *y) { - xcb_ungrab_pointer(_ecore_xcb_conn, XCB_CURRENT_TIME); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (x) *x = _ecore_xcb_event_last_root_x; + if (y) *y = _ecore_xcb_event_last_root_y; } -EAPI int -ecore_x_pointer_warp(Ecore_X_Window window, - int x, - int y) +EAPI void +ecore_x_focus_reset(void) { - xcb_warp_pointer(_ecore_xcb_conn, XCB_NONE, window, 0, 0, 0, 0, x, y); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return 1; + 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 int -ecore_x_keyboard_grab(Ecore_X_Window window) +EAPI void +ecore_x_events_allow_all(void) { - 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, window, - XCB_CURRENT_TIME, - XCB_GRAB_MODE_ASYNC, - XCB_GRAB_MODE_ASYNC); - reply = xcb_grab_keyboard_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - return 0; + xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME); +// ecore_x_flush(); +} - free(reply); +/** + * 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; - return 1; + 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_keyboard_ungrab(void) +ecore_x_killall(Ecore_X_Window root) { - xcb_ungrab_keyboard(_ecore_xcb_conn, XCB_CURRENT_TIME); + 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 } -EAPI void -ecore_x_grab(void) +/** + * 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) { - _ecore_xcb_grab_count++; + uint16_t mw = 0, w = 0; - if (_ecore_xcb_grab_count == 1) - xcb_grab_server(_ecore_xcb_conn); + 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; } -EAPI void -ecore_x_ungrab(void) +/** + * @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) { - _ecore_xcb_grab_count--; - if (_ecore_xcb_grab_count < 0) - _ecore_xcb_grab_count = 0; + char *gl = NULL; - if (_ecore_xcb_grab_count == 0) - { - xcb_ungrab_server(_ecore_xcb_conn); - free(xcb_get_input_focus_reply(_ecore_xcb_conn, xcb_get_input_focus(_ecore_xcb_conn), 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; } -int _ecore_window_grabs_num = 0; -Ecore_X_Window *_ecore_window_grabs = NULL; -int (*_ecore_window_grab_replay_func) (void *data, int event_type, void *event); -void *_ecore_window_grab_replay_data; +/** + * 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(int (*func) (void *data, - int event_type, - void *event), +ecore_x_passive_grab_replay_func_set(Eina_Bool (*func)(void *data, int type, void *event), void *data) { - _ecore_window_grab_replay_func = func; - _ecore_window_grab_replay_data = 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_window_button_grab(Ecore_X_Window window, - int button, - Ecore_X_Event_Mask event_mask, - int mod, - int any_mod) +ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h) { - int i; - uint16_t m; - uint16_t locks[8]; - uint16_t ev; - - m = mod; - if (any_mod) m = XCB_BUTTON_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 = event_mask; - for (i = 0; i < 8; i++) - xcb_grab_button(_ecore_xcb_conn, 0, window, ev, - XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, - XCB_NONE, XCB_NONE, button, m | locks[i]); - _ecore_window_grabs_num++; - _ecore_window_grabs = realloc(_ecore_window_grabs, - _ecore_window_grabs_num * sizeof(Ecore_X_Window)); - _ecore_window_grabs[_ecore_window_grabs_num - 1] = window; + 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; } -void -_ecore_x_sync_magic_send(int val, - Ecore_X_Window swindow) +/** + * 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) { - xcb_client_message_event_t ev; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.window = _ecore_xcb_private_window; - ev.type = 27777; - ev.data.data32[0] = 0x7162534; - ev.data.data32[1] = 0x10000000 + val; - ev.data.data32[2] = swindow; - - xcb_send_event(_ecore_xcb_conn, 0, _ecore_xcb_private_window, - XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); + return xcb_setup_roots_length(xcb_get_setup(_ecore_xcb_conn)); } -void -_ecore_x_window_grab_remove(Ecore_X_Window window) +/** + * 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) { - int i, shuffle = 0; + xcb_screen_iterator_t iter; + int i = 0; + + CHECK_XCB_CONN; - if (_ecore_window_grabs_num > 0) + iter = + xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); + for (; iter.rem; xcb_screen_next(&iter)) { - 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] == window)) - shuffle = 1; - } - if (shuffle) - { - _ecore_window_grabs_num--; - _ecore_window_grabs = realloc(_ecore_window_grabs, - _ecore_window_grabs_num * sizeof(Ecore_X_Window)); - } + if (iter.data == (xcb_screen_t *)screen) + return i; + i++; } + + return 0; } -EAPI void -ecore_x_window_button_ungrab(Ecore_X_Window window, - int button, - int mod, - int any_mod) +/** + * 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) { - int i; - uint16_t m; - uint16_t locks[8]; - - m = mod; - if (any_mod) m = XCB_BUTTON_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, button, window, m | locks[i]); - _ecore_x_sync_magic_send(1, window); -} + xcb_screen_iterator_t iter; + int i = 0; -int _ecore_key_grabs_num = 0; -Ecore_X_Window *_ecore_key_grabs = NULL; + CHECK_XCB_CONN; -EAPI void -ecore_x_window_key_grab(Ecore_X_Window window, - const char *key, - int mod, - int any_mod) + 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) { - xcb_keycode_t keycode = 0; - uint16_t m; - uint16_t locks[8]; - int i; - - if (!strncmp(key, "Keycode-", 8)) - keycode = atoi(key + 8); - /* FIXME: TODO... */ - -/* else */ -/* { */ -/* KeySym keysym; */ - -/* keysym = XStringToKeysym(key); */ -/* if (keysym == NoSymbol) return; */ -/* keycode = XKeysymToKeycode(_ecore_xcb_conn, XStringToKeysym(key)); */ -/* } */ - if (keycode == 0) return; - - m = mod; - if (any_mod) m = XCB_BUTTON_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, 1, window, m | locks[i], keycode, - XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); - _ecore_key_grabs_num++; - _ecore_key_grabs = realloc(_ecore_key_grabs, - _ecore_key_grabs_num * sizeof(Ecore_X_Window)); - _ecore_key_grabs[_ecore_key_grabs_num - 1] = window; + return ((xcb_visualtype_t *)visual)->visual_id; } -void -_ecore_x_key_grab_remove(Ecore_X_Window window) +/** + * 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) { - int i, shuffle = 0; + xcb_screen_t *s; + xcb_depth_iterator_t diter; + xcb_visualtype_iterator_t viter; + + CHECK_XCB_CONN; - if (_ecore_key_grabs_num > 0) + s = (xcb_screen_t *)screen; + diter = xcb_screen_allowed_depths_iterator(s); + for (; diter.rem; xcb_depth_next(&diter)) { - 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] == window)) - shuffle = 1; - } - if (shuffle) - { - _ecore_key_grabs_num--; - _ecore_key_grabs = realloc(_ecore_key_grabs, - _ecore_key_grabs_num * sizeof(Ecore_X_Window)); - } + 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; } -EAPI void -ecore_x_window_key_ungrab(Ecore_X_Window window, - const char *key, - int mod, - int any_mod) +/** + * 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_keycode_t keycode = 0; - uint16_t m; - uint16_t locks[8]; - int i; - - if (!strncmp(key, "Keycode-", 8)) - keycode = atoi(key + 8); - /* FIXME: todo... */ - -/* else */ -/* { */ -/* KeySym keysym; */ - -/* keysym = XStringToKeysym(key); */ -/* if (keysym == NoSymbol) return; */ -/* keycode = XKeysymToKeycode(_ecore_xcb_conn, XStringToKeysym(key)); */ -/* } */ - if (keycode == 0) return; - - m = mod; - if (any_mod) m = XCB_BUTTON_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, window, m | locks[i]); - _ecore_x_sync_magic_send(2, window); + xcb_screen_t *s; + + s = (xcb_screen_t *)screen; + return s->default_colormap; } /** - * Send client message with given type and format 32. + * Retrieve the default depth. * - * @param window The window the message is sent to. - * @param type The client message type. - * @param mask The client message mask. - * @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 + * @param disp The Display to get the Default Depth from + * @param screen The Screen. * - * @return !0 on success. + * @return The default depth. + * @since 1.1.0 */ EAPI int -ecore_x_client_message32_send(Ecore_X_Window window, - Ecore_X_Atom type, - Ecore_X_Event_Mask mask, - long d0, - long d1, - long d2, - long d3, - long d4) +ecore_x_default_depth_get(Ecore_X_Display *disp __UNUSED__, Ecore_X_Screen *screen) { - xcb_client_message_event_t ev; + xcb_screen_t *s; - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.window = window; - ev.type = type; - ev.data.data32[0] = d0; - ev.data.data32[1] = d1; - ev.data.data32[2] = d2; - ev.data.data32[3] = d3; - ev.data.data32[4] = d4; + s = (xcb_screen_t *)screen; + return s->root_depth; +} - xcb_send_event(_ecore_xcb_conn, 0, window, mask, (const char *)&ev); +EAPI void +ecore_x_xkb_select_group(int group) +{ + // XXX: implement me */ +} - return 1; +/** + * 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; } /** - * Send client message with given type and format 8. + * Retrieves the double and triple click flag timeout. * - * @param window 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 20. + * See @ref ecore_x_double_click_time_set for more information. * - * @return !0 on success. + * @return The timeout for double clicks in seconds. + * @ingroup Ecore_X_Display_Attr_Group */ -EAPI int -ecore_x_client_message8_send(Ecore_X_Window window, - Ecore_X_Atom type, - const void *data, - int len) +EAPI double +ecore_x_double_click_time_get(void) { - xcb_client_message_event_t ev; + return _ecore_xcb_double_click_time; +} - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 8; - ev.window = window; - ev.type = type; - if (len > 20) - len = 20; - memcpy(ev.data.data8, data, len); - memset(ev.data.data8 + len, 0, 20 - len); +/* local function prototypes */ +static int +_ecore_xcb_shutdown(Eina_Bool close_display) +{ + if (--_ecore_xcb_init_count != 0) + return _ecore_xcb_init_count; - xcb_send_event(_ecore_xcb_conn, 0, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); + if (!_ecore_xcb_conn) + return _ecore_xcb_init_count; - return 1; -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/* FIXME: round trip */ -EAPI int -ecore_x_mouse_move_send(Ecore_X_Window window, - int x, - int y) -{ - xcb_motion_notify_event_t ev; - xcb_get_geometry_cookie_t cookie_geom; - xcb_translate_coordinates_cookie_t cookie_trans; - xcb_get_geometry_reply_t *reply_geom; - xcb_translate_coordinates_reply_t *reply_trans; - - 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 0; - - cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y); - reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL); - if (!reply_trans) + 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 { - free(reply_geom); - return 0; + close(xcb_get_file_descriptor(_ecore_xcb_conn)); + _ecore_xcb_conn = NULL; } - ev.response_type = XCB_MOTION_NOTIFY; - ev.detail = 0; - ev.time = _ecore_xcb_event_last_time; - ev.root = reply_geom->root; - ev.event = window; - ev.child = window; - ev.root_x = reply_trans->dst_x; - ev.root_y = reply_trans->dst_y; - ev.event_x = x; - ev.event_y = y; - ev.state = 0; - ev.same_screen = 1; + /* shutdown events */ + _ecore_xcb_events_shutdown(); - xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_POINTER_MOTION, (const char *)&ev); + /* shutdown input extension */ + _ecore_xcb_input_shutdown(); - free(reply_geom); - free(reply_trans); + /* shutdown gesture extension */ + _ecore_xcb_gesture_shutdown(); - return 1; -} + /* shutdown selection */ + _ecore_xcb_selection_shutdown(); -/* FIXME: round trip */ -EAPI int -ecore_x_mouse_down_send(Ecore_X_Window window, - int x, - int y, - int button) -{ - xcb_button_press_event_t ev; - xcb_get_geometry_cookie_t cookie_geom; - xcb_translate_coordinates_cookie_t cookie_trans; - xcb_get_geometry_reply_t *reply_geom; - xcb_translate_coordinates_reply_t *reply_trans; - - 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 0; - - cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y); - reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL); - if (!reply_trans) - { - free(reply_geom); - return 0; - } + /* shutdown dnd */ + _ecore_xcb_dnd_shutdown(); - ev.response_type = XCB_BUTTON_PRESS; - ev.detail = button; - ev.time = _ecore_xcb_event_last_time; - ev.root = reply_geom->root; - ev.event = window; - ev.child = window; - ev.root_x = reply_trans->dst_x; - ev.root_y = reply_trans->dst_y; - ev.event_x = x; - ev.event_y = y; - ev.state = 1 << button; - ev.same_screen = 1; + /* shutdown netwm */ + ecore_x_netwm_shutdown(); - xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_BUTTON_PRESS, (const char *)&ev); + /* shutdown keymap */ + _ecore_xcb_keymap_shutdown(); - free(reply_geom); - free(reply_trans); + /* shutdown ecore_event */ + ecore_event_shutdown(); - return 1; + /* 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; } -/* FIXME: round trip */ -EAPI int -ecore_x_mouse_up_send(Ecore_X_Window window, - int x, - int y, - int button) +static Eina_Bool +_ecore_xcb_fd_handle(void *data, Ecore_Fd_Handler *hdlr __UNUSED__) { - xcb_button_release_event_t ev; - xcb_get_geometry_cookie_t cookie_geom; - xcb_translate_coordinates_cookie_t cookie_trans; - xcb_get_geometry_reply_t *reply_geom; - xcb_translate_coordinates_reply_t *reply_trans; - - 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 0; - - cookie_trans = xcb_translate_coordinates_unchecked(_ecore_xcb_conn, window, reply_geom->root, x, y); - reply_trans = xcb_translate_coordinates_reply(_ecore_xcb_conn, cookie_trans, NULL); - if (!reply_trans) + xcb_connection_t *conn; + xcb_generic_event_t *ev = NULL; + + conn = (xcb_connection_t *)data; + + if (_ecore_xcb_event_buffered) { - free(reply_geom); - return 0; + _ecore_xcb_events_handle(_ecore_xcb_event_buffered); + free(_ecore_xcb_event_buffered); + _ecore_xcb_event_buffered = NULL; } - ev.response_type = XCB_BUTTON_RELEASE; - ev.detail = button; - ev.time = _ecore_xcb_event_last_time; - ev.root = reply_geom->root; - ev.event = window; - ev.child = window; - ev.root_x = reply_trans->dst_x; - ev.root_y = reply_trans->dst_y; - ev.event_x = x; - ev.event_y = y; - ev.state = 0; - ev.same_screen = 1; - - xcb_send_event(_ecore_xcb_conn, 1, window, XCB_EVENT_MASK_BUTTON_RELEASE, (const char *)&ev); +// xcb_flush(conn); - free(reply_geom); - free(reply_trans); + 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 1; + return ECORE_CALLBACK_RENEW; } -EAPI void -ecore_x_focus_reset(void) +static Eina_Bool +_ecore_xcb_fd_handle_buff(void *data, Ecore_Fd_Handler *hdlr __UNUSED__) { - xcb_set_input_focus(_ecore_xcb_conn, - (uint8_t)XCB_INPUT_FOCUS_POINTER_ROOT, - XCB_INPUT_FOCUS_POINTER_ROOT, - XCB_CURRENT_TIME); -} + xcb_connection_t *conn; + xcb_generic_event_t *ev = NULL; -EAPI void -ecore_x_events_allow_all(void) -{ - xcb_allow_events(_ecore_xcb_conn, XCB_ALLOW_ASYNC_BOTH, XCB_CURRENT_TIME); -} + 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; -EAPI void -ecore_x_pointer_last_xy_get(int *x, - int *y) -{ - if (x) *x = _ecore_xcb_event_last_root_x; - if (y) *y = _ecore_xcb_event_last_root_y; + 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..c8c217e --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_atoms.c @@ -0,0 +1,149 @@ +#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. + * + * @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 index eefacba..0d3b44e 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_composite.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_composite.c @@ -1,68 +1,290 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" - -/** - * @defgroup Ecore_X_Composite_Group X Composite Extension Functions - * - * Functions related to the X Composite extension. - */ - #ifdef ECORE_XCB_COMPOSITE -static uint8_t _composite_available = 0; -static xcb_composite_query_version_cookie_t _ecore_xcb_composite_init_cookie; -#endif /* ECORE_XCB_COMPOSITE */ - +# include +#endif -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_composite_init and - _ecore_xcb_composite_init_finalize. The first one gets the cookies and - the second one gets the replies. */ +/* local variables */ +static Eina_Bool _composite_avail = EINA_FALSE; void -_ecore_x_composite_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_composite_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_COMPOSITE - if (reply && reply->present) - _ecore_xcb_composite_init_cookie = xcb_composite_query_version_unchecked(_ecore_xcb_conn, XCB_COMPOSITE_MAJOR_VERSION, XCB_COMPOSITE_MINOR_VERSION); -#endif /* ECORE_XCB_COMPOSITE */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_composite_id); +#endif } void -_ecore_x_composite_init_finalize(void) +_ecore_xcb_composite_finalize(void) { #ifdef ECORE_XCB_COMPOSITE - xcb_composite_query_version_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_composite_query_version_reply(_ecore_xcb_conn, - _ecore_xcb_composite_init_cookie, - NULL); - if (reply) + 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)) { - if (reply->major_version = XCB_COMPOSITE_MAJOR_VERSION && - reply->minor_version >= XCB_COMPOSITE_MINOR_VERSION) - _composite_available = 1; - free(reply); + 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 /* ECORE_XCB_COMPOSITE */ +#endif } /** - * Return whether the Composite Extension is available. - * @return 1 if the Composite Extension is available, 0 if not. + * @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. * - * Return 1 if the X server supports the Composite Extension version 0.4 - * or greater, 0 otherwise. * @ingroup Ecore_X_Composite_Group */ -EAPI int +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 - return _composite_available; + 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 0; -#endif /* ECORE_XCB_COMPOSITE */ + 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 index 1dcea4d..755df04 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_cursor.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_cursor.c @@ -1,23 +1,77 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" -#include -#include +#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 -extern int _ecore_xcb_xcursor; +void +_ecore_xcb_cursor_init(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + /* NB: No-op */ +} +void +_ecore_xcb_cursor_finalize(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); -EAPI int +#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) { - return _ecore_xcb_xcursor; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return _ecore_xcb_cursor; } EAPI Ecore_X_Cursor -ecore_x_cursor_new(Ecore_X_Window window, +ecore_x_cursor_new(Ecore_X_Window win, int *pixels, int w, int h, @@ -25,198 +79,169 @@ ecore_x_cursor_new(Ecore_X_Window window, 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_x_xcursor) + if (_ecore_xcb_cursor) { - 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; - } + 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_XCB_CURSOR */ - { - const uint32_t dither[2][2] = - { - {0, 2}, - {3, 1} - }; - Ecore_X_Drawable draw; - Ecore_X_Pixmap pixmap; - Ecore_X_Pixmap mask; - Ecore_X_GC gc; - xcb_image_t *image; - uint32_t *pix; - uint8_t fr; - uint8_t fg; - uint8_t fb; - uint8_t br; - uint8_t bg; - uint8_t bb; - uint32_t brightest = 0; - uint32_t darkest = 255 * 3; - uint16_t x; - uint16_t y; - - draw = window; - pixmap = xcb_generate_id(_ecore_xcb_conn); - xcb_create_pixmap(_ecore_xcb_conn, - 1, pixmap, draw, - 1, 1); - mask = xcb_generate_id(_ecore_xcb_conn); - xcb_create_pixmap(_ecore_xcb_conn, - 1, mask, draw, - 1, 1); - - image = xcb_image_create_native(_ecore_xcb_conn, w, h, - XCB_IMAGE_FORMAT_Z_PIXMAP, - 32, NULL, ~0, NULL); - image->data = malloc(image->size); - - fr = 0x00; fg = 0x00; fb = 0x00; - br = 0xff; bg = 0xff; bb = 0xff; - 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(image, x, y, v); - pix++; - } - } - draw = pixmap; - gc = xcb_generate_id(_ecore_xcb_conn); - xcb_create_gc(_ecore_xcb_conn, gc, draw, 0, NULL); - xcb_image_put(_ecore_xcb_conn, draw, gc, image, 0, 0, 0); - xcb_free_gc(_ecore_xcb_conn, 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(image, x, y, v); - pix++; - } - } - draw = mask; - gc = xcb_generate_id(_ecore_xcb_conn); - xcb_create_gc (_ecore_xcb_conn, gc, draw, 0, NULL); - xcb_image_put(_ecore_xcb_conn, draw, gc, image, 0, 0, 0); - xcb_free_gc(_ecore_xcb_conn, gc); - - free(image->data); - image->data = NULL; - xcb_image_destroy(image); - - cursor = xcb_generate_id(_ecore_xcb_conn); - xcb_create_cursor (_ecore_xcb_conn, cursor, - pixmap, 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, pixmap); - xcb_free_pixmap(_ecore_xcb_conn, mask); - - return cursor; - } +#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 cursor) +ecore_x_cursor_free(Ecore_X_Cursor c) { - xcb_free_cursor(_ecore_xcb_conn, cursor); +// LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_free_cursor(_ecore_xcb_conn, c); } /* @@ -227,44 +252,149 @@ ecore_x_cursor_free(Ecore_X_Cursor cursor) EAPI Ecore_X_Cursor ecore_x_cursor_shape_get(int shape) { - Ecore_X_Cursor cursor; - xcb_font_t font; + Ecore_X_Cursor cursor = 0; + xcb_font_t font; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* Shapes are defined in Ecore_X_Cursor.h */ font = xcb_generate_id(_ecore_xcb_conn); xcb_open_font(_ecore_xcb_conn, font, strlen("cursor"), "cursor"); cursor = xcb_generate_id(_ecore_xcb_conn); - xcb_create_glyph_cursor (_ecore_xcb_conn, - cursor, - font, - font, - shape, - shape + 1, - 0, 0, 0, - 65535, 65535, 65535); + /* 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) { -#ifdef ECORE_XCB_CURSOR - XcursorSetDefaultSize(_ecore_x_disp, size); -#else - size = 0; -#endif /* ECORE_XCB_CURSOR */ + 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 - return XcursorGetDefaultSize(_ecore_x_disp); -#else - return 0; -#endif /* 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 index d5b0c66..deb3b9c 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_damage.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_damage.c @@ -1,83 +1,79 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" +# ifdef ECORE_XCB_DAMAGE +# include +# endif +/* local variables */ +static Eina_Bool _damage_avail = EINA_FALSE; -/** - * @defgroup Ecore_X_Damage_Group X Damage Extension Functions - * - * Functions related to the X Damage extension. - */ - - -#ifdef ECORE_XCB_DAMAGE -static uint8_t _damage_available = 0; -static xcb_damage_query_version_cookie_t _ecore_xcb_damage_init_cookie; -#endif /* ECORE_XCB_DAMAGE */ - - -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_damage_init and - _ecore_xcb_damage_init_finalize. The first one gets the cookies and - the second one gets the replies. */ +/* external variables */ +int _ecore_xcb_event_damage = -1; void -_ecore_x_damage_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_damage_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_DAMAGE - if (reply && (reply->present)) - _ecore_xcb_damage_init_cookie = xcb_damage_query_version_unchecked(_ecore_xcb_conn, 1, 1); -#endif /* ECORE_XCB_DAMAGE */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_damage_id); +#endif } void -_ecore_x_damage_init_finalize(void) +_ecore_xcb_damage_finalize(void) { #ifdef ECORE_XCB_DAMAGE - xcb_damage_query_version_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_damage_query_version_reply(_ecore_xcb_conn, - _ecore_xcb_damage_init_cookie, - NULL); - if (reply) + 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)) { - if (reply->major_version >= 1) - _damage_available = 1; - free(reply); + 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 /* ECORE_XCB_DAMAGE */ +#endif } - /** - * Return whether the Damage Extension is available. - * @return 1 if the Damage Extension is available, 0 if not. + * @defgroup Ecore_X_Damage_Group X Damage Extension Functions * - * Return 1 if the X server supports the Damage Extension version 1.0, - * 0 otherwise. - * @ingroup Ecore_X_Damage_Group + * Functions related to the X Damage Extension. */ -EAPI int + +EAPI Eina_Bool ecore_x_damage_query(void) { -#ifdef ECORE_XCB_DAMAGE - return _damage_available; -#else - return 0; -#endif /* ECORE_XCB_DAMAGE */ + return _damage_avail; } - /** - * Creates a damage object. - * @param drawable The drawable to monotor. - * @param level The level of the damage report. - * @return The damage object. + * 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. * - * Creates a damage object to monitor changes to @p drawable, with the - * level @p level. * @ingroup Ecore_X_Damage_Group */ EAPI Ecore_X_Damage @@ -86,45 +82,59 @@ ecore_x_damage_new(Ecore_X_Drawable drawable, { 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); -#endif /* ECORE_XCB_DAMAGE */ +// ecore_x_flush(); +#endif return damage; } - /** - * Destroys a damage object. - * @param damage The damage object to destroy. + * Destroy a damage object + * + * @param damage The damage object to destroy + * + * Destroys the damage object @p damage * - * Destroys the damage object @p damage. * @ingroup Ecore_X_Damage_Group */ EAPI void -ecore_x_damage_del(Ecore_X_Damage damage) +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); -#endif /* ECORE_XCB_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 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 = + * 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 @@ -132,7 +142,14 @@ 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); -#endif /* ECORE_XCB_DAMAGE */ +// 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 index b270d3d..177e61d 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_dnd.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_dnd.c @@ -1,751 +1,688 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include "Ecore.h" #include "ecore_xcb_private.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; +#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 int _ecore_x_dnd_init_count = 0; - +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_x_dnd_init(void) +_ecore_xcb_dnd_init(void) { - if (!_ecore_x_dnd_init_count) - { + LOGFN(__FILE__, __LINE__, __FUNCTION__); - _source = calloc(1, sizeof(Ecore_X_DND_Source)); - _source->version = ECORE_X_DND_VERSION; - _source->win = XCB_NONE; - _source->dest = XCB_NONE; - _source->state = ECORE_X_DND_SOURCE_IDLE; - - _target = calloc(1, sizeof(Ecore_X_DND_Target)); - _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(); + 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_x_dnd_init_count++; + _ecore_xcb_dnd_init_count++; } void -_ecore_x_dnd_shutdown(void) +_ecore_xcb_dnd_shutdown(void) { - _ecore_x_dnd_init_count--; - if (_ecore_x_dnd_init_count > 0) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (_source) - free(_source); + _ecore_xcb_dnd_init_count--; + if (_ecore_xcb_dnd_init_count > 0) return; + if (_source) free(_source); _source = NULL; - - if (_target) - free(_target); + if (_target) free(_target); _target = NULL; - - _ecore_x_dnd_init_count = 0; + _ecore_xcb_dnd_init_count = 0; } EAPI void -ecore_x_dnd_aware_set(Ecore_X_Window window, - int on) +ecore_x_dnd_send_status(Eina_Bool will_accept, + Eina_Bool suppress, + Ecore_X_Rectangle rect, + Ecore_X_Atom action) { - Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; + xcb_client_message_event_t ev; - if (on) - ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_AWARE, - ECORE_X_ATOM_ATOM, 32, &prop_data, 1); - else - ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_AWARE); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - */ -EAPI void -ecore_x_dnd_version_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_XDND_AWARE, - ECORE_X_ATOM_ATOM, - 0, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); -} + if (_target->state == ECORE_X_DND_TARGET_IDLE) return; + memset(&ev, 0, sizeof(xcb_client_message_event_t)); -/** - * Gets the reply of the GetProperty request sent by ecore_x_dnd_version_get_prefetch(). - */ -EAPI void -ecore_x_dnd_version_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + _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; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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(); } -/** - * Get the DnD version. - * @param window Unused. - * @return 0 on failure, the version otherwise. - * - * Get the DnD version. Returns 0 on failure, the version otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_dnd_version_get_prefetch(), which sends the GetProperty request, - * then ecore_x_dnd_version_get_fetch(), which gets the reply. - */ -EAPI int -ecore_x_dnd_version_get(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_dnd_drop(void) { - unsigned char *prop_data; - int num; + xcb_client_message_event_t ev; + Eina_Bool status = EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_AWARE, - ECORE_X_ATOM_ATOM, 32, &prop_data, &num)) + memset(&ev, 0, sizeof(xcb_client_message_event_t)); + + if (_source->dest) { - int version = (int) *prop_data; - free(prop_data); - return version; + 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 - return 0; -} + { + ecore_x_selection_xdnd_clear(); + _source->state = ECORE_X_DND_SOURCE_IDLE; + } -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - */ -EAPI void -ecore_x_dnd_type_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 0, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); -} + ecore_x_window_ignore_set(_source->win, 0); + _source->prev.window = 0; + return status; +} -/** - * Gets the reply of the GetProperty request sent by ecore_x_dnd_type_get_prefetch(). - */ EAPI void -ecore_x_dnd_type_get_fetch(void) +ecore_x_dnd_aware_set(Ecore_X_Window win, + Eina_Bool on) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + Ecore_X_Atom prop_data = ECORE_X_DND_VERSION; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); -/* FIXME: round trip (InternAtomGet request) */ + 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); +} -/** - * Check if the type is set. - * @param window Unused. - * @param type The type to check - * @return 0 on failure, 1 otherwise. - * - * Check if the type is set. 0 on failure, 1 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request, - * then ecore_x_dnd_type_get_fetch(), which gets the reply. - */ EAPI int -ecore_x_dnd_type_isset(Ecore_X_Window window, - const char *type) +ecore_x_dnd_version_get(Ecore_X_Window win) { - xcb_intern_atom_cookie_t cookie; - xcb_intern_atom_reply_t *reply; - Ecore_X_Atom *atoms; - unsigned char *data; - int num; - int i; - uint8_t ret = 0; - - cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, - strlen(type), type); - - if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, 32, &data, &num)) + unsigned char *data; + int num = 0; + Version_Cache_Item *t; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (_source->state == ECORE_X_DND_SOURCE_DRAGGING) { - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (reply) free(reply); - return ret; + 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; + } + } } - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) + 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); - return 0; + 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; } - atoms = (Ecore_X_Atom *)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 = 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 (reply->atom == atoms[i]) - { - ret = 1; - break; - } + if (atom == atoms[i]) + { + ret = EINA_TRUE; + break; + } } free(data); - free(reply); - return ret; } -/* FIXME: round trip (InternAtomGet request) */ - -/** - * Set the type. - * @param window Unused. - * @param type The type to set - * @param on 0 or non 0... - * - * Set the type. - * - * To use this function, you must call before, and in order, - * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request, - * then ecore_x_dnd_type_get_fetch(), which gets the reply. - */ EAPI void -ecore_x_dnd_type_set(Ecore_X_Window window, +ecore_x_dnd_type_set(Ecore_X_Window win, const char *type, - int on) + Eina_Bool on) { - xcb_intern_atom_cookie_t cookie; - xcb_intern_atom_reply_t *reply; - Ecore_X_Atom *oldset = NULL; - Ecore_X_Atom *newset = NULL; - unsigned char *data = NULL; - unsigned char *old_data = NULL; - Ecore_X_Atom atom; - int i, j = 0, num = 0; - - cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, - strlen(type), type); + 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); - if (!ecore_x_window_prop_property_get(window, ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 32, &old_data, &num)) - { - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (reply) free(reply); - return; - } + 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(window, type)) - { - free(old_data); - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (reply) free(reply); - return; - } - data = calloc(num + 1, sizeof(Ecore_X_Atom)); - if (!data) + if (ecore_x_dnd_type_isset(win, type)) { - free(old_data); - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (reply) free(reply); + free(old_data); return; } - newset = (Ecore_X_Atom *)data; - - for (i = 0; i < num; i++) - newset[i + 1] = oldset[i]; - /* prepend the new type */ - - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - { - free(old_data); - return; - } - newset[0] = reply->atom; - free(reply); - - ecore_x_window_prop_property_set(window, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 32, data, num + 1); + 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(window, 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(window, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 32, data, num - 1); + 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); } -/* FIXME: round trips, but I don't think we can do much, here */ - -/** - * Set the types. - * @param window Unused. - * @param types The types to set - * @param num_types The number of types - * - * Set the types. - * - * To use this function, you must call before, and in order, - * ecore_x_dnd_type_get_prefetch(), which sends the GetProperty request, - * then ecore_x_dnd_type_get_fetch(), which gets the reply. - */ EAPI void -ecore_x_dnd_types_set(Ecore_X_Window window, - char **types, +ecore_x_dnd_types_set(Ecore_X_Window win, + const char **types, unsigned int num_types) { Ecore_X_Atom *newset = NULL; - void *data = NULL; - uint32_t i; + unsigned int i; + unsigned char *data = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; if (!num_types) - { - ecore_x_window_prop_property_del(window, ECORE_X_ATOM_XDND_TYPE_LIST); - } + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_TYPE_LIST); else { - xcb_intern_atom_cookie_t *cookies; - xcb_intern_atom_reply_t *reply; - - cookies = (xcb_intern_atom_cookie_t *)malloc(sizeof(xcb_intern_atom_cookie_t)); - if (!cookies) return; - for (i = 0; i < num_types; i++) - cookies[i] = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, - strlen(types[i]), types[i]); - data = calloc(num_types, sizeof(Ecore_X_Atom)); - if (!data) + newset = calloc(num_types, sizeof(Ecore_X_Atom)); + if (!newset) return; + + data = (unsigned char *)newset; + for (i = 0; i < num_types; i++) { - for (i = 0; i < num_types; i++) - { - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL); - if (reply) free(reply); - } - free(cookies); - return; + newset[i] = ecore_x_atom_get(types[i]); + ecore_x_selection_converter_atom_add(newset[i], + _ecore_xcb_dnd_converter_copy); } - newset = data; - for (i = 0; i < num_types; i++) - { - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookies[i], NULL); - if (reply) - { - newset[i] = reply->atom; - free(reply); - } - else - newset[i] = XCB_NONE; - } - free(cookies); - ecore_x_window_prop_property_set(window, ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, 32, data, num_types); - free(data); + ecore_x_window_prop_property_set(win, ECORE_X_ATOM_XDND_TYPE_LIST, + ECORE_X_ATOM_ATOM, 32, data, + num_types); + free(newset); } } -Ecore_X_DND_Source * -_ecore_x_dnd_source_get(void) +EAPI void +ecore_x_dnd_actions_set(Ecore_X_Window win, + Ecore_X_Atom *actions, + unsigned int num_actions) { - return _source; -} + unsigned int i; + unsigned char *data = NULL; -Ecore_X_DND_Target * -_ecore_x_dnd_target_get(void) -{ - return _target; -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * Sends the GetProperty request. - * @param source Window whose properties are requested. - */ -EAPI void -ecore_x_dnd_begin_prefetch(Ecore_X_Window source) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - source ? source : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_XDND_AWARE, - ECORE_X_ATOM_ATOM, - 0, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); + 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); + } } - /** - * Gets the reply of the GetProperty request sent by ecore_x_dnd_begin_prefetch(). + * 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_begin_fetch(void) +ecore_x_dnd_callback_pos_update_set(void (*cb)(void *, Ecore_X_Xdnd_Position *data), + const void *data) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + _posupdatecb = cb; + _posupdatedata = (void *)data; } -/* FIXME: round trip */ - -/** - * Begins the DnD. - * @param source Unused. - * @param data The data. - * @param size The size of the data. - * @return 0 on failure, 1 otherwise. - * - * Begins the DnD. Returns 0 on failure, 1 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_dnd_begin_prefetch(), which sends the GetProperty request, - * then ecore_x_dnd_begin_fetch(), which gets the reply. - */ -EAPI int +EAPI Eina_Bool ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size) { - ecore_x_selection_xdnd_prefetch(); - if (!ecore_x_dnd_version_get(source)) + 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) { - ecore_x_selection_xdnd_fetch(); - return 0; + free(_version_cache); + _version_cache = NULL; + _version_cache_num = 0; + _version_cache_alloc = 0; } - /* Take ownership of XdndSelection */ - ecore_x_selection_xdnd_prefetch(); - ecore_x_selection_xdnd_fetch(); - if (!ecore_x_selection_xdnd_set(source, data, size)) - return 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_event_last_time; + _source->time = _ecore_xcb_events_last_time_get(); + _source->prev.window = 0; - /* Default Accepted Action: ask */ - _source->action = ECORE_X_ATOM_XDND_ACTION_COPY; + /* Default Accepted Action: move */ + _source->action = ECORE_X_ATOM_XDND_ACTION_MOVE; _source->accepted_action = XCB_NONE; - return 1; -} - -EAPI int -ecore_x_dnd_drop(void) -{ - uint8_t status = 0; - - if (_source->dest) - { - xcb_client_message_event_t ev; - - 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, 0, (const char *)&ev); - _source->state = ECORE_X_DND_SOURCE_DROPPED; - status = 1; - } - 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, 0, (const char *)&ev); - _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->dest = XCB_NONE; - return status; + return EINA_TRUE; } EAPI void -ecore_x_dnd_send_status(int will_accept, - int suppress, - Ecore_X_Rectangle rectangle, - Ecore_X_Atom action) +ecore_x_dnd_send_finished(void) { xcb_client_message_event_t ev; - if (_target->state == ECORE_X_DND_TARGET_IDLE) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - _target->will_accept = will_accept; + 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.type = ECORE_X_ATOM_XDND_STATUS; - 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; - - /* Set rectangle information */ - ev.data.data32[2] = rectangle.x; - ev.data.data32[2] <<= 16; - ev.data.data32[2] |= rectangle.y; - ev.data.data32[3] = rectangle.width; - ev.data.data32[3] <<= 16; - ev.data.data32[3] |= rectangle.height; - - if (will_accept) - { - ev.data.data32[4] = action; - _target->accepted_action = action; - } - else + ev.data.data32[2] = 0; + if (_target->will_accept) { - ev.data.data32[4] = XCB_NONE; - _target->accepted_action = action; + ev.data.data32[1] |= 0x1UL; + ev.data.data32[2] = _target->accepted_action; } - xcb_send_event(_ecore_xcb_conn, 0, _target->source, 0, (const char *)&ev); + 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_send_finished(void) +ecore_x_dnd_source_action_set(Ecore_X_Atom action) { - xcb_client_message_event_t ev; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (_target->state == ECORE_X_DND_TARGET_IDLE) - return; - - ev.response_type = XCB_CLIENT_MESSAGE; - ev.format = 32; - ev.window = _target->source; - ev.type = ECORE_X_ATOM_XDND_FINISHED; + _source->action = action; + if (_source->prev.window) + _ecore_xcb_dnd_drag(_source->prev.window, + _source->prev.x, _source->prev.y); +} - 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, 0, (const char *)&ev); +Ecore_X_DND_Source * +_ecore_xcb_dnd_source_get(void) +{ + return _source; +} - _target->state = ECORE_X_DND_TARGET_IDLE; +Ecore_X_DND_Target * +_ecore_xcb_dnd_target_get(void) +{ + return _target; } void -_ecore_x_dnd_drag(Ecore_X_Window root, - int x, - int y) +_ecore_xcb_dnd_drag(Ecore_X_Window root, + int x, + int y) { xcb_client_message_event_t ev; - Ecore_X_Window win; - Ecore_X_Window *skip; - int num; + Ecore_X_Window win, *skip; + Ecore_X_Xdnd_Position pos; + int num = 0; + + if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return; - 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; - /* Attempt to find a DND-capable window under the cursor */ skip = ecore_x_window_ignore_list(&num); -// 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); - while (win) + while ((win) && !(ecore_x_dnd_version_get(win))) + win = ecore_x_window_shadow_parent_get(root, win); + + if ((_source->dest) && (win != _source->dest)) { - xcb_query_tree_cookie_t cookie_tree; - xcb_query_tree_reply_t *reply_tree; + 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; + } - ecore_x_dnd_version_get_prefetch(win); - cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, win); + if (win) + { + int x1, x2, y1, y2; - ecore_x_dnd_version_get_fetch(); - /* We found the correct window ? */ - if (ecore_x_dnd_version_get(win)) + _source->version = MIN(ECORE_X_DND_VERSION, + ecore_x_dnd_version_get(win)); + if (win != _source->dest) { - reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); - if (reply_tree) free(reply_tree); - break; + 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; } - reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); - if (reply_tree) + + 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))) { - win = reply_tree->parent; - free(reply_tree); + 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; } } - /* Send XdndLeave to current destination window if we have left it */ - if ((_source->dest) && (win != _source->dest)) + if (_posupdatecb) { - 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, 0, (const char *)&ev); - _source->suppress = 0; + pos.position.x = x; + pos.position.y = y; + pos.win = win; + pos.prev = _source->dest; + _posupdatecb(_posupdatedata, &pos); } - if (win) - { - int16_t x1; - int16_t x2; - int16_t y1; - int16_t y2; + _source->prev.x = x; + _source->prev.y = y; + _source->prev.window = root; + _source->dest = win; +} - ecore_x_dnd_version_get_prefetch(win); - ecore_x_dnd_type_get_prefetch(_source->win); +EAPI Ecore_X_Atom +ecore_x_dnd_source_action_get(void) +{ + return _source->action; +} - ecore_x_dnd_version_get_fetch(); - if (!ecore_x_dnd_version_get(win)) +/* 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))) { - ecore_x_dnd_type_get_fetch(); - return; + free(mystr); + return EINA_FALSE; } - - _source->version = MIN(ECORE_X_DND_VERSION, - ecore_x_dnd_version_get(win)); - if (win != _source->dest) - { - unsigned char *data; - Ecore_X_Atom *types; - int num; - int i; - - ecore_x_dnd_type_get_fetch(); - if (!ecore_x_window_prop_property_get(_source->win, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 32, &data, &num)) - return; - - types = (Ecore_X_Atom *)data; - - /* Entered new window, send XdndEnter */ - 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, 0, (const char *)&ev); - _source->await_status = 0; - _source->will_accept = 0; - } - else - ecore_x_dnd_type_get_fetch(); - - /* 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))) - { - ev.window = win; - ev.type = ECORE_X_ATOM_XDND_POSITION; - ev.data.data32[0] = _source->win; - ev.data.data32[1] = 0; /* Reserved */ - ev.data.data32[2] = ((x << 16) & 0xffff0000) | (y & 0xffff); - ev.data.data32[3] = _source->time; /* Version 1 */ - ev.data.data32[4] = _source->action; /* Version 2, Needs to be pre-set */ - xcb_send_event(_ecore_xcb_conn, 0, win, 0, (const char *)&ev); - - _source->await_status = 1; - } + 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; } - - _source->dest = win; } + diff --git a/src/lib/ecore_x/xcb/ecore_xcb_dpms.c b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c index cb61d45..39ef589 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_dpms.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_dpms.c @@ -1,194 +1,139 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" +#ifdef ECORE_XCB_DAMAGE +# include +#endif - -/** - * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions - * - * Functions related to the X DPMS extension. - */ - - -#ifdef ECORE_XCB_DPMS -static int _dpms_available = 0; -static xcb_dpms_get_version_cookie_t _ecore_xcb_dpms_init_cookie; -#endif /* ECORE_XCB_DPMS */ - -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_dpms_init and - _ecore_xcb_dpms_init_finalize. The first one gets the cookies and - the second one gets the replies. */ +/* local variables */ +static Eina_Bool _dpms_avail = EINA_FALSE; void -_ecore_x_dpms_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_dpms_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_DPMS - if (reply && (reply->present)) - _ecore_xcb_dpms_init_cookie = xcb_dpms_get_version_unchecked(_ecore_xcb_conn, 0, 0); -#endif /* ECORE_XCB_DPMS */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_dpms_id); +#endif } void -_ecore_x_dpms_init_finalize(void) +_ecore_xcb_dpms_finalize(void) { #ifdef ECORE_XCB_DPMS - xcb_dpms_get_version_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_dpms_get_version_reply(_ecore_xcb_conn, - _ecore_xcb_dpms_init_cookie, NULL); + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (reply) +#ifdef ECORE_XCB_DPMS + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_dpms_id); + if ((ext_reply) && (ext_reply->present)) { - if (reply->server_major_version >= 1) - _dpms_available = 1; - free(reply); + 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 /* ECORE_XCB_DPMS */ +#endif } - /** - * Checks if the DPMS extension is available or not. - * @return @c 1 if the DPMS extension is available, @c 0 otherwise. + * @defgroup Ecore_X_DPMS_Group X DPMS Extension Functions * - * Return 1 if the X server supports the DPMS Extension version 1.0, - * 0 otherwise. - * @ingroup Ecore_X_DPMS_Group + * Functions related to the X DPMS Extension */ -EAPI int -ecore_x_dpms_query(void) -{ -#ifdef ECORE_XCB_DPMS - return _dpms_available; -#else - return 0; -#endif /* ECORE_XCB_DPMS */ -} - /** - * Sends the DPMSCapable request. - * @ingroup Ecore_X_DPMS_Group - */ -EAPI void -ecore_x_dpms_capable_get_prefetch(void) -{ -#ifdef ECORE_XCB_DPMS - xcb_dpms_capable_cookie_t cookie; - - cookie = xcb_dpms_capable_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_DPMS */ -} - - -/** - * Gets the reply of the DPMSCapable request sent by ecore_x_dpms_capable_get_prefetch(). + * 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 void -ecore_x_dpms_capable_get_fetch(void) +EAPI Eina_Bool +ecore_x_dpms_query(void) { -#ifdef ECORE_XCB_DPMS - xcb_dpms_capable_cookie_t cookie; - xcb_dpms_capable_reply_t *reply; +// LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_dpms_capable_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_DPMS */ + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_capable_get_prefetch(), which sends the DPMSCapable request, - * then ecore_x_dpms_capable_get_fetch(), which gets the reply. * @ingroup Ecore_X_DPMS_Group */ -EAPI int +EAPI Eina_Bool ecore_x_dpms_capable_get(void) { - int capable = 0; + Eina_Bool ret = EINA_FALSE; #ifdef ECORE_XCB_DPMS + xcb_dpms_capable_cookie_t cookie; xcb_dpms_capable_reply_t *reply; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - capable = reply->capable; -#endif /* ECORE_XCB_DPMS */ + if (!_dpms_avail) return EINA_FALSE; - return capable; -} - - -/** - * Sends the DPMSInfo request. - * @ingroup Ecore_X_DPMS_Group - */ -EAPI void -ecore_x_dpms_enable_get_prefetch(void) -{ #ifdef ECORE_XCB_DPMS - xcb_dpms_info_cookie_t cookie; + 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 - cookie = xcb_dpms_info_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_DPMS */ + return ret; } - /** - * Gets the reply of the DPMSInfo request sent by ecore_x_dpms_enable_get_prefetch(). + * 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 void -ecore_x_dpms_enable_get_fetch(void) +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 - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_dpms_info_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_DPMS */ -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + if (!_dpms_avail) return EINA_FALSE; -/** - * Checks the DPMS state of the display. - * @return @c 1 if DPMS is enabled, @c 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_enapable_get_prefetch(), which sends the DPMSInfo request, - * then ecore_x_dpms_enapable_get_fetch(), which gets the reply. - * @ingroup Ecore_X_DPMS_Group - */ -EAPI int -ecore_x_dpms_enable_get(void) -{ - int enable = 0; #ifdef ECORE_XCB_DPMS - xcb_dpms_info_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; - - enable = reply->state; -#endif /* 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 enable; + return ret; } - /** * Sets the DPMS state of the display. * @param enabled @c 0 to disable DPMS characteristics of the server, enable it otherwise. @@ -197,255 +142,179 @@ ecore_x_dpms_enable_get(void) 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); + xcb_dpms_enable(_ecore_xcb_conn); else - xcb_dpms_disable(_ecore_xcb_conn); -#endif /* ECORE_XCB_DPMS */ + xcb_dpms_disable(_ecore_xcb_conn); +#endif } - /** - * Sets the timeouts. The values are in unit of seconds. + * 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. - * @return Returns always 1. - * @ingroup Ecore_X_DPMS_Group - */ -EAPI int -ecore_x_dpms_timeouts_set(unsigned int standby, - unsigned int suspend, - unsigned int off) -{ -#ifdef ECORE_XCB_DPMS - xcb_dpms_set_timeouts(_ecore_xcb_conn, standby, suspend, off); -#endif /* ECORE_XCB_DPMS */ - - return 1; -} - - -/** - * Sends the DPMSGetTimeouts request. * @ingroup Ecore_X_DPMS_Group */ EAPI void -ecore_x_dpms_timeouts_get_prefetch(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 - cookie = xcb_dpms_get_timeouts_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_DPMS */ -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + if (standby) *standby = 0; + if (suspend) *suspend = 0; + if (off) *off = 0; -/** - * Gets the reply of the DPMSGetTimeouts request sent by ecore_x_dpms_timeouts_get_prefetch(). - * @ingroup Ecore_X_DPMS_Group - */ -EAPI void -ecore_x_dpms_timeouts_get_fetch(void) -{ -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_cookie_t cookie; - xcb_dpms_get_timeouts_reply_t *reply; + if (!_dpms_avail) return; - cookie.sequence = _ecore_xcb_cookie_get(); +#ifdef ECORE_XCB_DPMS + cookie = xcb_dpms_get_timeouts_unchecked(_ecore_xcb_conn); reply = xcb_dpms_get_timeouts_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_DPMS */ + if (!reply) return; + if (standby) *standby = reply->standby_timeout; + if (suspend) *suspend = reply->suspend_timeout; + if (off) *off = reply->off_timeout; + free(reply); +#endif } - /** - * Gets the timeouts. The values are in unit of seconds. + * 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 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) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!_dpms_avail) return EINA_FALSE; + #ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; + // FIXME: Add request check + xcb_dpms_set_timeouts(_ecore_xcb_conn, standby, suspend, off); + return EINA_TRUE; +#endif - reply = _ecore_xcb_reply_get(); - if (reply) - { - if (standby) *standby = reply->standby_timeout; - if (suspend) *suspend = reply->suspend_timeout; - if (off) *off = 0; - } - else -#endif /* ECORE_XCB_DPMS */ - { - if (standby) *standby = 0; - if (suspend) *suspend = 0; - if (off) *off = 0; - } + return EINA_FALSE; } - /** * Returns the amount of time of inactivity before standby mode is invoked. * @return The standby timeout value. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int ecore_x_dpms_timeout_standby_get(void) { - int standby = 0; -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + unsigned int standby = 0; - standby = reply->standby_timeout; -#endif /* ECORE_XCB_DPMS */ + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int ecore_x_dpms_timeout_suspend_get(void) { - int suspend = 0;; -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + unsigned int suspend = 0; - suspend = reply->suspend_timeout; -#endif /* ECORE_XCB_DPMS */ + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int ecore_x_dpms_timeout_off_get(void) { - int off = 0; -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + unsigned int off = 0; - off = reply->off_timeout; -#endif /* ECORE_XCB_DPMS */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_dpms_timeouts_get(NULL, NULL, &off); return off; } - /** * Sets the standby timeout (in unit of seconds). - * @param new_standby Amount of time of inactivity before standby mode will be invoked. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. + * @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_standby) +ecore_x_dpms_timeout_standby_set(unsigned int new_timeout) { -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; + unsigned int standby = 0, suspend = 0, off = 0; - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - xcb_dpms_set_timeouts(_ecore_xcb_conn, - new_standby, - reply->suspend_timeout, - reply->off_timeout); -#endif /* ECORE_XCB_DPMS */ + 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 suspend Amount of time of inactivity before the screen is placed into suspend mode. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. + * @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_suspend) +ecore_x_dpms_timeout_suspend_set(unsigned int new_timeout) { -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; + unsigned int standby = 0, suspend = 0, off = 0; - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - xcb_dpms_set_timeouts(_ecore_xcb_conn, - reply->standby_timeout, - new_suspend, - reply->off_timeout); -#endif /* ECORE_XCB_DPMS */ + 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 off Amount of time of inactivity before the monitor is shut off. - * - * To use this function, you must call before, and in order, - * ecore_x_dpms_timeouts_get_prefetch(), which sends the DPMSGetTimeouts request, - * then ecore_x_dpms_timeouts_get_fetch(), which gets the reply. + * @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_off) +ecore_x_dpms_timeout_off_set(unsigned int new_timeout) { -#ifdef ECORE_XCB_DPMS - xcb_dpms_get_timeouts_reply_t *reply; + unsigned int standby = 0, suspend = 0, off = 0; - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - xcb_dpms_set_timeouts(_ecore_xcb_conn, - reply->standby_timeout, - reply->suspend_timeout, - new_off); -#endif /* ECORE_XCB_DPMS */ + 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 index 3a1bb5b..4e9a356 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_drawable.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_drawable.c @@ -1,10 +1,4 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" -#include - /** * @defgroup Ecore_X_Drawable_Group X Drawable Functions @@ -12,118 +6,118 @@ * Functions that operate on drawables. */ - -/** - * Sends the GetGeometry request. - * @param drawable Drawable whose characteristics are sought. - * @ingroup Ecore_X_Drawable_Group - */ -EAPI void -ecore_x_drawable_geometry_get_prefetch(Ecore_X_Drawable drawable) -{ - xcb_get_geometry_cookie_t cookie; - - cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, drawable); - _ecore_xcb_cookie_cache(cookie.sequence); -} - - /** - * Gets the reply of the GetGeometry request sent by ecore_x_atom_get_prefetch(). - * @ingroup Ecore_X_Drawable_Group + * 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_geometry_get_fetch(void) +ecore_x_drawable_rectangle_fill(Ecore_X_Drawable draw, + Ecore_X_GC gc, + int x, + int y, + int w, + int h) { - xcb_get_geometry_cookie_t cookie; - xcb_get_geometry_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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 drawable Unused. - * @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 width Pointer to an integer into which the width is to be stored. - * @param height Pointer to an integer into which the height is to be stored. - * - * To use this function, you must call before, and in order, - * ecore_x_drawable_geometry_get_prefetch(), which sends the GetGeometry request, - * then ecore_x_drawable_geometry_get_fetch(), which gets the reply. + * @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 drawable __UNUSED__, +ecore_x_drawable_geometry_get(Ecore_X_Drawable draw, int *x, int *y, - int *width, - int *height) + int *w, + int *h) { + xcb_get_geometry_cookie_t cookie; xcb_get_geometry_reply_t *reply; - reply = _ecore_xcb_reply_get(); - if (!reply) - { - if (x) *x = 0; - if (y) *y = 0; - if (width) *width = 0; - if (height) *height = 0; - return; - } + 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 (width) *width = reply->width; - if (height) *height = reply->height; + 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 drawable Unused. - * @return The border width of the given drawable. - * - * To use this function, you must call before, and in order, - * ecore_x_drawable_geometry_get_prefetch(), which sends the GetGeometry request, - * then ecore_x_drawable_geometry_get_fetch(), which gets the reply. + * @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 drawable __UNUSED__) +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; - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return reply->border_width; + 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 drawable Unused. - * @return The depth of the given drawable. - * - * To use this function, you must call before, and in order, - * ecore_x_drawable_geometry_get_prefetch(), which sends the GetGeometry request, - * then ecore_x_drawable_geometry_get_fetch(), which gets the reply. + * @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 drawable __UNUSED__) +ecore_x_drawable_depth_get(Ecore_X_Drawable d) { + xcb_get_geometry_cookie_t cookie; xcb_get_geometry_reply_t *reply; + int ret = 0; - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return reply->depth; + 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 index 4c82617..82d94b6 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_e.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_e.c @@ -1,17 +1,435 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#include "ecore_xcb_private.h" -/* - * OLD E hints - */ +/* 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); -#include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" +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 window, +ecore_x_e_frame_size_set(Ecore_X_Window win, int fl, int fr, int ft, @@ -19,11 +437,1140 @@ ecore_x_e_frame_size_set(Ecore_X_Window window, { uint32_t frames[4]; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + frames[0] = fl; frames[1] = fr; frames[2] = ft; frames[3] = fb; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_E_FRAME_SIZE, ECORE_X_ATOM_CARDINAL, 32, - 4, (const void *)frames); + 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_access_action_up_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_UP, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_down_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_DOWN, + 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 index bf6799a..1763397 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_events.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_events.c @@ -1,914 +1,912 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include "Ecore.h" #include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.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 -/** OpenBSD does not define CODESET - * FIXME ?? - */ +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; + +EAPI int ECORE_X_RAW_BUTTON_PRESS = 0; +EAPI int ECORE_X_RAW_BUTTON_RELEASE = 0; +EAPI int ECORE_X_RAW_MOTION = 0; -#ifndef CODESET -#define CODESET "INVALID" +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(); + + ECORE_X_RAW_BUTTON_PRESS = ecore_event_type_new(); + ECORE_X_RAW_BUTTON_RELEASE = ecore_event_type_new(); + ECORE_X_RAW_MOTION = 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; + } -#if 0 -static void _ecore_x_event_free_window_prop_name_class_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_title_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_visible_title_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_icon_name_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_visible_icon_name_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_client_machine_change(void *data, void *ev); + /* 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 -static void _ecore_x_event_free_key_down(void *data, void *ev); -static void _ecore_x_event_free_key_up(void *data, void *ev); +#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 +} -static Ecore_X_Window _ecore_xcb_mouse_down_last_window = 0; -static Ecore_X_Window _ecore_xcb_mouse_down_last_last_window = 0; -static Ecore_X_Window _ecore_xcb_mouse_down_last_event_window = 0; -static Ecore_X_Window _ecore_xcb_mouse_down_last_last_event_window = 0; -static Ecore_X_Time _ecore_xcb_mouse_down_last_time = 0; -static Ecore_X_Time _ecore_xcb_mouse_down_last_last_time = 0; -static int _ecore_xcb_mouse_up_count = 0; -static int _ecore_xcb_mouse_down_did_triple = 0; +Ecore_X_Time +_ecore_xcb_events_last_time_get(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_xcb_event_last_time; +} -/* FIXME: roundtrip */ EAPI void -ecore_x_event_mask_set(Ecore_X_Window window, +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 value_list; + uint32_t list; - if (!window) - window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); + 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; - value_list = mask | reply->your_event_mask; - xcb_change_window_attributes(_ecore_xcb_conn, window, XCB_CW_EVENT_MASK, &value_list); + list = (mask | reply->your_event_mask); free(reply); + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); } -/* FIXME: roundtrip */ EAPI void -ecore_x_event_mask_unset(Ecore_X_Window window, +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 value_list; + uint32_t list; - if (!window) - window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); + 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; - value_list = reply->your_event_mask & ~mask; - xcb_change_window_attributes(_ecore_xcb_conn, window, XCB_CW_EVENT_MASK, &value_list); + list = (reply->your_event_mask & ~mask); free(reply); + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_EVENT_MASK, &list); +// ecore_x_flush(); } -#if 0 -static void -_ecore_x_event_free_window_prop_name_class_change(void *data, void *ev) -{ - Ecore_X_Event_Window_Prop_Name_Class_Change *e; - - e = ev; - if (e->name) free(e->name); - if (e->clas) free(e->clas); - free(e); -} - -static void -_ecore_x_event_free_window_prop_title_change(void *data, void *ev) -{ - Ecore_X_Event_Window_Prop_Title_Change *e; - - e = ev; - if (e->title) free(e->title); - free(e); -} - -static void -_ecore_x_event_free_window_prop_visible_title_change(void *data, void *ev) -{ - Ecore_X_Event_Window_Prop_Visible_Title_Change *e; - - e = ev; - if (e->title) free(e->title); - free(e); -} - -static void -_ecore_x_event_free_window_prop_icon_name_change(void *data, void *ev) -{ - Ecore_X_Event_Window_Prop_Icon_Name_Change *e; - - e = ev; - if (e->name) free(e->name); - free(e); -} - -static void -_ecore_x_event_free_window_prop_visible_icon_name_change(void *data, void *ev) +unsigned int +_ecore_xcb_events_modifiers_get(unsigned int state) { - Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change *e; - - e = ev; - if (e->name) free(e->name); - free(e); + 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_x_event_free_window_prop_client_machine_change(void *data, void *ev) +_ecore_xcb_event_handle_any_event(xcb_generic_event_t *event) { - Ecore_X_Event_Window_Prop_Client_Machine_Change *e; + xcb_generic_event_t *ev; - e = ev; - if (e->name) free(e->name); - free(e); -} -#endif +// LOGFN(__FILE__, __LINE__, __FUNCTION__); -static void -_ecore_x_event_free_key_down(void *data __UNUSED__, void *ev) -{ - Ecore_X_Event_Key_Down *e; + ev = malloc(sizeof(xcb_generic_event_t)); + if (!ev) return; - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->key_compose) free(e->key_compose); - free(e); + memcpy(ev, event, sizeof(xcb_generic_event_t)); + ecore_event_add(ECORE_X_EVENT_ANY, ev, NULL, NULL); } static void -_ecore_x_event_free_key_up(void *data __UNUSED__, void *ev) +_ecore_xcb_event_handle_key_press(xcb_generic_event_t *event) { - Ecore_X_Event_Key_Up *e; - - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->key_compose) free(e->key_compose); - free(e); + _ecore_xcb_event_key_press(event); } static void -_ecore_x_event_free_xdnd_enter(void *data __UNUSED__, void *ev) +_ecore_xcb_event_handle_key_release(xcb_generic_event_t *event) { - Ecore_X_Event_Xdnd_Enter *e; - int i; - - e = ev; - for (i = 0; i < e->num_types; i++) - free(e->types[i]); - free(e->types); - free(e); + _ecore_xcb_event_key_release(event); } 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); -} - -/* FIXME: handle this event */ -void -_ecore_x_event_handle_key_press(xcb_generic_event_t *event) -{ - xcb_key_press_event_t *ev; -/* Ecore_X_Event_Key_Down *e; */ -/* char *keyname; */ -/* int val; */ -/* char buf[256]; */ -/* KeySym sym; */ -/* XComposeStatus status; */ - - ev = (xcb_key_press_event_t *)event; -/* e = calloc(1, sizeof(Ecore_X_Event_Key_Down)); */ -/* if (!e) return; */ -/* keyname = XKeysymToString(XKeycodeToKeysym(xevent->xkey.display, */ -/* xevent->xkey.keycode, 0)); */ -/* if (!keyname) */ -/* { */ -/* snprintf(buf, sizeof(buf), "Keycode-%i", xevent->xkey.keycode); */ -/* keyname = buf; */ -/* } */ -/* e->keyname = strdup(keyname); */ -/* if (!e->keyname) */ -/* { */ -/* free(e); */ -/* return; */ -/* } */ -/* val = XLookupString((XKeyEvent *)xevent, buf, sizeof(buf), &sym, &status); */ -/* if (val > 0) */ -/* { */ -/* buf[val] = 0; */ -/* e->key_compose = ecore_txt_convert(nl_langinfo(CODESET), "UTF-8", buf); */ -/* } */ -/* else e->key_compose = NULL; */ -/* keyname = XKeysymToString(sym); */ -/* if (keyname) e->keysymbol = strdup(keyname); */ -/* else e->keysymbol = strdup(e->keyname); */ -/* if (!e->keysymbol) */ -/* { */ -/* if (e->keyname) free(e->keyname); */ -/* if (e->key_compose) free(e->key_compose); */ -/* free(e); */ -/* return; */ -/* } */ -/* if (xevent->xkey.subwindow) e->win = xevent->xkey.subwindow; */ -/* else e->win = xevent->xkey.window; */ -/* e->event_win = xevent->xkey.window; */ -/* e->time = xevent->xkey.time; */ -/* e->modifiers = xevent->xkey.state; */ -/* _ecore_x_event_last_time = e->time; */ -/* ecore_event_add(ECORE_X_EVENT_KEY_DOWN, e, _ecore_x_event_free_key_down, NULL); */ -} - -/* FIXME: handle this event */ -void -_ecore_x_event_handle_key_release(xcb_generic_event_t *event) -{ - xcb_key_release_event_t *ev; -/* Ecore_X_Event_Key_Up *e; */ -/* char *keyname; */ -/* int val; */ -/* char buf[256]; */ -/* KeySym sym; */ -/* XComposeStatus status; */ - - ev = (xcb_key_release_event_t *)event; -/* e = calloc(1, sizeof(Ecore_X_Event_Key_Up)); */ -/* if (!e) return; */ -/* keyname = XKeysymToString(XKeycodeToKeysym(xevent->xkey.display, */ -/* xevent->xkey.keycode, 0)); */ -/* if (!keyname) */ -/* { */ -/* snprintf(buf, sizeof(buf), "Keycode-%i", xevent->xkey.keycode); */ -/* keyname = buf; */ -/* } */ -/* e->keyname = strdup(keyname); */ -/* if (!e->keyname) */ -/* { */ -/* free(e); */ -/* return; */ -/* } */ -/* val = XLookupString((XKeyEvent *)xevent, buf, sizeof(buf), &sym, &status); */ -/* if (val > 0) */ -/* { */ -/* buf[val] = 0; */ -/* e->key_compose = ecore_txt_convert("ISO8859-1", "UTF-8", buf); */ -/* } */ -/* else e->key_compose = NULL; */ -/* keyname = XKeysymToString(sym); */ -/* if (keyname) e->keysymbol = strdup(keyname); */ -/* else e->keysymbol = strdup(e->keyname); */ -/* if (!e->keysymbol) */ -/* { */ -/* if (e->keyname) free(e->keyname); */ -/* if (e->key_compose) free(e->key_compose); */ -/* free(e); */ -/* return; */ -/* } */ -/* if (xevent->xkey.subwindow) e->win = xevent->xkey.subwindow; */ -/* else e->win = xevent->xkey.window; */ -/* e->event_win = xevent->xkey.window; */ -/* e->time = xevent->xkey.time; */ -/* e->modifiers = xevent->xkey.state; */ -/* _ecore_x_event_last_time = e->time; */ -/* ecore_event_add(ECORE_X_EVENT_KEY_UP, e, _ecore_x_event_free_key_up, NULL); */ -} - -void -_ecore_x_event_handle_button_press(xcb_generic_event_t *event) +_ecore_xcb_event_handle_button_press(xcb_generic_event_t *event) { xcb_button_press_event_t *ev; - int i; + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; ev = (xcb_button_press_event_t *)event; if ((ev->detail > 3) && (ev->detail < 8)) { - Ecore_X_Event_Mouse_Wheel *e; - - e = malloc(sizeof(Ecore_X_Event_Mouse_Wheel)); - - if (!e) - return; - - e->modifiers = ev->state; - e->direction = 0; - e->z = 0; - if (ev->detail == 4) - { - e->direction = 0; - e->z = -1; - } - else if (ev->detail == 5) - { - e->direction = 0; - e->z = 1; - } - else if (ev->detail == 6) - { - e->direction = 1; - e->z = -1; - } - else if (ev->detail == 7) - { - e->direction = 1; - e->z = 1; - } - 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; - e->root_win = ev->root; - 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_WHEEL, e, NULL, NULL); - for (i = 0; i < _ecore_window_grabs_num; i++) - { - if ((_ecore_window_grabs[i] == ev->event) || - (_ecore_window_grabs[i] == ev->child)) - { - int replay = 0; - - if (_ecore_window_grab_replay_func) - replay = _ecore_window_grab_replay_func(_ecore_window_grab_replay_data, - ECORE_X_EVENT_MOUSE_WHEEL, - e); - /* FIXME: xcb_key_press_event_t does not save the */ - /* connection. So I use the current one */ - if (replay) - xcb_allow_events(_ecore_xcb_conn, - XCB_ALLOW_REPLAY_POINTER, - ev->time); - else - xcb_allow_events(_ecore_xcb_conn, - XCB_ALLOW_ASYNC_POINTER, - ev->time); - break; - } - } + 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_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen; - e->root_win = ev->root; - e->event_win = ev->event; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Button_Down *e; - - if (_ecore_xcb_mouse_down_did_triple) - { - _ecore_xcb_mouse_down_last_window = 0; - _ecore_xcb_mouse_down_last_last_window = 0; - _ecore_xcb_mouse_down_last_event_window = 0; - _ecore_xcb_mouse_down_last_last_event_window = 0; - _ecore_xcb_mouse_down_last_time = 0; - _ecore_xcb_mouse_down_last_last_time = 0; - } - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Button_Down)); - if (!e) return; - e->button = ev->detail; - e->modifiers = 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->same_screen = ev->same_screen; - e->root_win = ev->root; - e->event_win = ev->event; - e->time = ev->time; - if (e->win == e->event_win) - { - if (((int)(e->time - _ecore_xcb_mouse_down_last_time) <= - (int)(1000 * _ecore_xcb_double_click_time)) && - (e->win == _ecore_xcb_mouse_down_last_window) && - (e->event_win == _ecore_xcb_mouse_down_last_event_window) - ) - e->double_click = 1; - if (((int)(e->time - _ecore_xcb_mouse_down_last_last_time) <= - (int)(2 * 1000 * _ecore_xcb_double_click_time)) && - (e->win == _ecore_xcb_mouse_down_last_window) && - (e->win == _ecore_xcb_mouse_down_last_last_window) && - (e->event_win == _ecore_xcb_mouse_down_last_event_window) && - (e->event_win == _ecore_xcb_mouse_down_last_last_event_window) - ) - { - e->triple_click = 1; - _ecore_xcb_mouse_down_did_triple = 1; - } - else - _ecore_xcb_mouse_down_did_triple = 0; - } - if (!e->double_click && !e->triple_click) - _ecore_xcb_mouse_up_count = 0; - _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_BUTTON_DOWN, e, NULL, NULL); - for (i = 0; i < _ecore_window_grabs_num; i++) - { - if ((_ecore_window_grabs[i] == ev->event) || - (_ecore_window_grabs[i] == ev->child)) - { - int replay = 0; - - if (_ecore_window_grab_replay_func) - replay = _ecore_window_grab_replay_func(_ecore_window_grab_replay_data, - ECORE_X_EVENT_MOUSE_BUTTON_DOWN, - e); - /* FIXME: xcb_key_press_event_t does not save the */ - /* connection. So I use the current one */ - if (replay) - xcb_allow_events(_ecore_xcb_conn, - XCB_ALLOW_REPLAY_POINTER, - ev->time); - else - xcb_allow_events(_ecore_xcb_conn, - XCB_ALLOW_ASYNC_POINTER, - ev->time); - break; - } - } - if (e->win == e->event_win) - { - if (!_ecore_xcb_mouse_down_did_triple) - { - _ecore_xcb_mouse_down_last_last_window = _ecore_xcb_mouse_down_last_window; - if (ev->child) - _ecore_xcb_mouse_down_last_window = ev->child; - else - _ecore_xcb_mouse_down_last_window = ev->event; - _ecore_xcb_mouse_down_last_last_event_window = _ecore_xcb_mouse_down_last_event_window; - _ecore_xcb_mouse_down_last_event_window = ev->event; - _ecore_xcb_mouse_down_last_last_time = _ecore_xcb_mouse_down_last_time; - _ecore_xcb_mouse_down_last_time = ev->time; - } - } - } + 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); } } -void -_ecore_x_event_handle_button_release(xcb_generic_event_t *event) +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; - /* filter out wheel buttons */ if ((ev->detail <= 3) || (ev->detail > 7)) { - { - Ecore_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen; - e->root_win = ev->root; - e->event_win = ev->event; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Button_Up *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Button_Up)); - if (!e) return; - e->button = ev->detail; - e->modifiers = 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->same_screen = ev->same_screen; - e->root_win = ev->root; - e->event_win = ev->event; - e->time = ev->time; - _ecore_xcb_mouse_up_count++; - if (e->win == e->event_win) - { - if ((_ecore_xcb_mouse_up_count >= 2) && - ((int)(e->time - _ecore_xcb_mouse_down_last_time) <= - (int)(1000 * _ecore_xcb_double_click_time)) && - (e->win == _ecore_xcb_mouse_down_last_window) && - (e->event_win == _ecore_xcb_mouse_down_last_event_window) - ) - e->double_click = 1; - if ((_ecore_xcb_mouse_up_count >= 3) && - ((int)(e->time - _ecore_xcb_mouse_down_last_last_time) <= - (int)(2 * 1000 * _ecore_xcb_double_click_time)) && - (e->win == _ecore_xcb_mouse_down_last_window) && - (e->win == _ecore_xcb_mouse_down_last_last_window) && - (e->event_win == _ecore_xcb_mouse_down_last_event_window) && - (e->event_win == _ecore_xcb_mouse_down_last_last_event_window) - ) - e->triple_click = 1; - } - _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_BUTTON_UP, e, NULL, 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_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); } } -void -_ecore_x_event_handle_motion_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_motion_notify(xcb_generic_event_t *event) { xcb_motion_notify_event_t *ev; - Ecore_X_Event_Mouse_Move *e; ev = (xcb_motion_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = ev->state; + + /* 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->same_screen = ev->same_screen; - e->root_win = ev->root; + 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; - /* Xdnd handling */ - _ecore_x_dnd_drag(e->root_win, e->root.x, e->root.y); - - ecore_event_add(ECORE_X_EVENT_MOUSE_MOVE, e, NULL, NULL); + ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, NULL); } -void -_ecore_x_event_handle_enter_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_leave_notify(xcb_generic_event_t *event) { - xcb_enter_notify_event_t *ev; + 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_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen_focus; - e->root_win = ev->root; - e->event_win = ev->event; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_In *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_In)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen_focus; - e->root_win = ev->root; - e->event_win = ev->event; - switch (ev->mode) { - case XCB_NOTIFY_MODE_NORMAL: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - case XCB_NOTIFY_MODE_GRAB: - e->mode = ECORE_X_EVENT_MODE_GRAB; - break; - case XCB_NOTIFY_MODE_UNGRAB: - e->mode = ECORE_X_EVENT_MODE_UNGRAB; - break; - default: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - } - switch (ev->detail) { - case XCB_NOTIFY_DETAIL_ANCESTOR: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - case XCB_NOTIFY_DETAIL_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_INFERIOR: - e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; - break; - default: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - } - e->time = ev->time; - _ecore_xcb_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_MOUSE_IN, e, NULL, 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_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); } -void -_ecore_x_event_handle_leave_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_keymap_notify(xcb_generic_event_t *event __UNUSED__) { - xcb_leave_notify_event_t *ev; +// LOGFN(__FILE__, __LINE__, __FUNCTION__); - ev = (xcb_leave_notify_event_t *)event; - { - Ecore_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen_focus; - e->root_win = ev->root; - e->event_win = ev->event; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Out *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out)); - if (!e) return; - e->modifiers = 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->same_screen = ev->same_screen_focus; - e->root_win = ev->root; - e->event_win = ev->event; - switch (ev->mode) { - case XCB_NOTIFY_MODE_NORMAL: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - case XCB_NOTIFY_MODE_GRAB: - e->mode = ECORE_X_EVENT_MODE_GRAB; - break; - case XCB_NOTIFY_MODE_UNGRAB: - e->mode = ECORE_X_EVENT_MODE_UNGRAB; - break; - default: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - } - switch (ev->detail) { - case XCB_NOTIFY_DETAIL_ANCESTOR: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - case XCB_NOTIFY_DETAIL_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_INFERIOR: - e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; - break; - default: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - } - 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); - } + // FIXME: handle this event type + _ecore_xcb_event_last_mouse_move = EINA_FALSE; } -void -_ecore_x_event_handle_focus_in(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_focus_in(xcb_generic_event_t *event) { - xcb_focus_in_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In)); - if (!e) return; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_In)))) return; + e->win = ev->event; - switch (ev->mode) { - case XCB_NOTIFY_MODE_NORMAL: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - case XCB_NOTIFY_MODE_GRAB: - e->mode = ECORE_X_EVENT_MODE_GRAB; - break; - case XCB_NOTIFY_MODE_UNGRAB: - e->mode = ECORE_X_EVENT_MODE_UNGRAB; - break; - case XCB_NOTIFY_MODE_WHILE_GRABBED: - e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED; - break; - } - switch (ev->detail) { - case XCB_NOTIFY_DETAIL_ANCESTOR: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - case XCB_NOTIFY_DETAIL_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_INFERIOR: - e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_POINTER: - e->detail = ECORE_X_EVENT_DETAIL_POINTER; - break; - case XCB_NOTIFY_DETAIL_POINTER_ROOT: - e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT; - break; - case XCB_NOTIFY_DETAIL_NONE: - e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE; - break; - } + 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); } -void -_ecore_x_event_handle_focus_out(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_focus_out(xcb_generic_event_t *event) { - xcb_focus_out_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out)); - if (!e) return; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Focus_Out)))) return; + e->win = ev->event; - switch (ev->mode) { - case XCB_NOTIFY_MODE_NORMAL: - e->mode = ECORE_X_EVENT_MODE_NORMAL; - break; - case XCB_NOTIFY_MODE_GRAB: - e->mode = ECORE_X_EVENT_MODE_GRAB; - break; - case XCB_NOTIFY_MODE_UNGRAB: - e->mode = ECORE_X_EVENT_MODE_UNGRAB; - break; - case XCB_NOTIFY_MODE_WHILE_GRABBED: - e->mode = ECORE_X_EVENT_MODE_WHILE_GRABBED; - break; - } - switch (ev->detail) { - case XCB_NOTIFY_DETAIL_ANCESTOR: - e->detail = ECORE_X_EVENT_DETAIL_ANCESTOR; - break; - case XCB_NOTIFY_DETAIL_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_INFERIOR: - e->detail = ECORE_X_EVENT_DETAIL_INFERIOR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR; - break; - case XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL: - e->detail = ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL; - break; - case XCB_NOTIFY_DETAIL_POINTER: - e->detail = ECORE_X_EVENT_DETAIL_POINTER; - break; - case XCB_NOTIFY_DETAIL_POINTER_ROOT: - e->detail = ECORE_X_EVENT_DETAIL_POINTER_ROOT; - break; - case XCB_NOTIFY_DETAIL_NONE: - e->detail = ECORE_X_EVENT_DETAIL_DETAIL_NONE; - break; - } + 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); -} -void -_ecore_x_event_handle_keymap_notify(xcb_generic_event_t *event __UNUSED__) -{ - /* FIXME: handle this event type */ + ecore_event_add(ECORE_X_EVENT_WINDOW_FOCUS_OUT, e, NULL, NULL); } -void -_ecore_x_event_handle_expose(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_expose(xcb_generic_event_t *event) { - xcb_expose_event_t *ev; + xcb_expose_event_t *ev; Ecore_X_Event_Window_Damage *e; - ev = (xcb_expose_event_t *)event, - e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)); - if (!e) return; + _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; @@ -916,151 +914,178 @@ _ecore_x_event_handle_expose(xcb_generic_event_t *event) e->w = ev->width; e->h = ev->height; e->count = ev->count; + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); } -void -_ecore_x_event_handle_graphics_expose(xcb_generic_event_t *event) +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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)); - if (!e) return; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Window_Damage)))) return; + e->win = ev->drawable; - 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; + e->time = _ecore_xcb_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_DAMAGE, e, NULL, NULL); } -void -_ecore_x_event_handle_visibility_notify(xcb_generic_event_t *event) +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 (ev->state != XCB_VISIBILITY_PARTIALLY_OBSCURED) - { - Ecore_X_Event_Window_Visibility_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Visibility_Change)); - if (!e) 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); - } + 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); } -void -_ecore_x_event_handle_create_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_create_notify(xcb_generic_event_t *event) { - xcb_create_notify_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Create)); - if (!e) return; + 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; + e->override = 1; else - e->override = 0; + 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); } -void -_ecore_x_event_handle_destroy_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_destroy_notify(xcb_generic_event_t *event) { - xcb_destroy_notify_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Destroy)); - if (!e) return; - e->win = ev->window; + 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; - if (e->win == _ecore_xcb_event_last_window) _ecore_xcb_event_last_window = 0; + ecore_event_add(ECORE_X_EVENT_WINDOW_DESTROY, e, NULL, NULL); } -void -_ecore_x_event_handle_unmap_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_map_notify(xcb_generic_event_t *event) { - xcb_unmap_notify_event_t *ev; - Ecore_X_Event_Window_Hide *e; + 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; - ev = (xcb_unmap_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Window_Hide)); - if (!e) 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); + + ecore_event_add(ECORE_X_EVENT_WINDOW_SHOW, e, NULL, NULL); } -void -_ecore_x_event_handle_map_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_unmap_notify(xcb_generic_event_t *event) { - xcb_map_notify_event_t *ev; - Ecore_X_Event_Window_Show *e; + 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; - ev = (xcb_map_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Window_Show)); - if (!e) 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); + + ecore_event_add(ECORE_X_EVENT_WINDOW_HIDE, e, NULL, NULL); } -void -_ecore_x_event_handle_map_request(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_map_request(xcb_generic_event_t *event) { - xcb_map_request_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Show_Request)); - if (!e) return; + 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); } -void -_ecore_x_event_handle_reparent_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_reparent_notify(xcb_generic_event_t *event) { - xcb_reparent_notify_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Reparent)); - if (!e) return; + 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); } -void -_ecore_x_event_handle_configure_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_configure_notify(xcb_generic_event_t *event) { - xcb_configure_notify_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Configure)); - if (!e) return; + 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; @@ -1069,21 +1094,25 @@ _ecore_x_event_handle_configure_notify(xcb_generic_event_t *event) 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->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); } -void -_ecore_x_event_handle_configure_request(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_configure_request(xcb_generic_event_t *event) { - xcb_configure_request_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Configure_Request)); - if (!e) return; + 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; @@ -1091,58 +1120,80 @@ _ecore_x_event_handle_configure_request(xcb_generic_event_t *event) 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); -} + switch (ev->stack_mode) + { + case XCB_STACK_MODE_ABOVE: + e->detail = ECORE_X_WINDOW_STACK_ABOVE; + break; -void -_ecore_x_event_handle_gravity_notify(xcb_generic_event_t *event __UNUSED__) -{ - /* FIXME: handle this event type */ + 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); } -void -_ecore_x_event_handle_resize_request(xcb_generic_event_t *event) +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; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Resize_Request)); - if (!e) return; + 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); } -void -_ecore_x_event_handle_circulate_notify(xcb_generic_event_t *event) +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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Stack)); - if (!e) return; + 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) @@ -1150,18 +1201,20 @@ _ecore_x_event_handle_circulate_notify(xcb_generic_event_t *event) 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); } -void -_ecore_x_event_handle_circulate_request(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_circulate_request(xcb_generic_event_t *event) { - xcb_circulate_request_event_t *ev; + 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Stack_Request)); - if (!e) return; + 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) @@ -1169,249 +1222,154 @@ _ecore_x_event_handle_circulate_request(xcb_generic_event_t *event) 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); } -void -_ecore_x_event_handle_property_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_property_notify(xcb_generic_event_t *event) { -#if 0 /* for now i disabled this. nice idea though this is - it leaves a lot - * to be desired for efficiency that is better left to the app layer - */ - if (xevent->xproperty.atom == ECORE_X_ATOM_WM_CLASS) - { - Ecore_X_Event_Window_Prop_Name_Class_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Name_Class_Change)); - if (!e) return; - ecore_x_window_prop_name_class_get(xevent->xproperty.window, - &(e->name), &(e->clas)); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE, e, _ecore_x_event_free_window_prop_name_class_change, NULL); - } - else if ((xevent->xproperty.atom == ECORE_X_ATOM_WM_NAME) || (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_NAME)) - { - Ecore_X_Event_Window_Prop_Title_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Title_Change)); - if (!e) return; - e->title = ecore_x_window_prop_title_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_TITLE_CHANGE, e, _ecore_x_event_free_window_prop_title_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_VISIBLE_NAME) - { - Ecore_X_Event_Window_Prop_Visible_Title_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Visible_Title_Change)); - if (!e) return; - e->title = ecore_x_window_prop_visible_title_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE, e, _ecore_x_event_free_window_prop_visible_title_change, NULL); - } - else if ((xevent->xproperty.atom == ECORE_X_ATOM_WM_ICON_NAME) || (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_ICON_NAME)) - { - Ecore_X_Event_Window_Prop_Icon_Name_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Icon_Name_Change)); - if (!e) return; - e->name = ecore_x_window_prop_icon_name_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE, e, _ecore_x_event_free_window_prop_icon_name_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME) - { - Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change)); - if (!e) return; - e->name = ecore_x_window_prop_visible_icon_name_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE, e, _ecore_x_event_free_window_prop_visible_icon_name_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_WM_CLIENT_MACHINE) - { - Ecore_X_Event_Window_Prop_Client_Machine_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Client_Machine_Change)); - if (!e) return; - e->name = ecore_x_window_prop_client_machine_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE, e, _ecore_x_event_free_window_prop_client_machine_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_PID) - { - Ecore_X_Event_Window_Prop_Pid_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Pid_Change)); - if (!e) return; - e->pid = ecore_x_window_prop_pid_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE, e, NULL, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_DESKTOP) - { - Ecore_X_Event_Window_Prop_Desktop_Change *e; + xcb_property_notify_event_t *ev; + Ecore_X_Event_Window_Property *e; - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Desktop_Change)); - if (!e) return; - e->desktop = ecore_x_window_prop_desktop_get(xevent->xproperty.window); - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE, e, NULL, NULL); - } - else -#endif - { - 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; - ev = (xcb_property_notify_event_t *)event; - e = calloc(1,sizeof(Ecore_X_Event_Window_Property)); - if (!e) 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); - } + ecore_event_add(ECORE_X_EVENT_WINDOW_PROPERTY, e, NULL, NULL); } -void -_ecore_x_event_handle_selection_clear(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_selection_clear(xcb_generic_event_t *event) { - xcb_selection_clear_event_t *ev; - Ecore_X_Selection_Intern *d; + xcb_selection_clear_event_t *ev; Ecore_X_Event_Selection_Clear *e; - Ecore_X_Atom sel; + Ecore_X_Atom sel; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _ecore_xcb_event_last_mouse_move = EINA_FALSE; ev = (xcb_selection_clear_event_t *)event; - if (!(d = _ecore_x_selection_get(ev->selection))) - return; - if (ev->time > d->time) - { - _ecore_x_selection_set(XCB_NONE, NULL, 0, - ev->selection); - } + if (!(e = malloc(sizeof(Ecore_X_Event_Selection_Clear)))) return; - /* Generate event for app cleanup */ - e = malloc(sizeof(Ecore_X_Event_Selection_Clear)); e->win = ev->owner; - e->time = ev->time; - sel = ev->selection; + 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 + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) e->selection = ECORE_X_SELECTION_CLIPBOARD; - ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL); + else + e->selection = ECORE_X_SELECTION_OTHER; + e->time = ev->time; + ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL); } -void -_ecore_x_event_handle_selection_request(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_selection_request(xcb_generic_event_t *event) { xcb_selection_request_event_t *ev; - Ecore_X_Selection_Intern *sd; - xcb_selection_notify_event_t sn_event; - void *data; + 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; - /* FIXME: is it the correct value ? */ - sn_event.response_type = XCB_SELECTION_NOTIFY; - sn_event.pad0 = 0; - /* FIXME: is it the correct value ? */ - sn_event.sequence = 0; - sn_event.time = XCB_CURRENT_TIME; - sn_event.requestor = ev->requestor; - sn_event.selection = ev->selection; - sn_event.target = ev->target; - - if ((sd = _ecore_x_selection_get(ev->selection)) && + 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)) { - if (!ecore_x_selection_convert(ev->selection, ev->target, - &data)) - { - /* Refuse selection, conversion to requested target failed */ - sn_event.property = XCB_NONE; - } - else - { - /* FIXME: This does not properly handle large data transfers */ - ecore_x_window_prop_property_set(ev->requestor, - ev->property, - ev->target, - 8, data, sd->length); - sn_event.property = ev->property; - free(data); - } - } - else - { - sn_event.property = XCB_NONE; - return; + 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); + } } - - /* FIXME: I use _ecore_xcb_conn, as ev has no information on the connection */ - xcb_send_event(_ecore_xcb_conn, 0, - ev->requestor, 0, (const char *)&sn_event); } -/* FIXME: round trip */ -void -_ecore_x_event_handle_selection_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_selection_notify(xcb_generic_event_t *event) { - xcb_selection_notify_event_t *ev; + xcb_selection_notify_event_t *ev; Ecore_X_Event_Selection_Notify *e; - unsigned char *data = NULL; - Ecore_X_Atom selection; - int num_ret; - uint8_t format; + 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) { - ecore_x_window_prop_property_get_prefetch(ev->requestor, - ev->property, - ECORE_X_ATOM_ATOM); - ecore_x_window_prop_property_get_fetch(); - format = ecore_x_window_prop_property_get(ev->requestor, - ev->property, - ECORE_X_ATOM_ATOM, - 32, - &data, - &num_ret); - if (!format) return; + 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 { - ecore_x_window_prop_property_get_prefetch(ev->requestor, - ev->property, - XCB_GET_PROPERTY_TYPE_ANY); - ecore_x_window_prop_property_get_fetch(); - format = ecore_x_window_prop_property_get(ev->requestor, - ev->property, - ECORE_X_ATOM_ATOM, - 8, - &data, - &num_ret); - if (!format) return; + 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->target = _ecore_x_selection_target_get(ev->target); + 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; @@ -1422,662 +1380,1449 @@ _ecore_x_event_handle_selection_notify(xcb_generic_event_t *event) else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) e->selection = ECORE_X_SELECTION_CLIPBOARD; else - { - free(e); - return; - } - e->data = _ecore_x_selection_parse(e->target, data, num_ret, format); + 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_x_event_free_selection_notify, NULL); + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, + _ecore_xcb_event_selection_notify_free, NULL); } -void -_ecore_x_event_handle_colormap_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_colormap_notify(xcb_generic_event_t *event) { - xcb_colormap_notify_event_t *ev; + 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; - e = calloc(1,sizeof(Ecore_X_Event_Window_Colormap)); - if (!e) return; + 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; + e->installed = 1; else - e->installed = 0; + e->installed = 0; e->time = _ecore_xcb_event_last_time; + ecore_event_add(ECORE_X_EVENT_WINDOW_COLORMAP, e, NULL, NULL); } -void -_ecore_x_event_handle_client_message(xcb_generic_event_t *event) +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 */ - xcb_client_message_event_t *ev; - - ev = (xcb_client_message_event_t *)event; - if ((ev->type == ECORE_X_ATOM_WM_PROTOCOLS) && - (ev->format == 32) && - (ev->data.data32[0] == (uint32_t)ECORE_X_ATOM_WM_DELETE_WINDOW)) + 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; + Ecore_X_Event_Window_Delete_Request *e; - e = calloc(1, sizeof(Ecore_X_Event_Window_Delete_Request)); - if (!e) return; - e->win = ev->window; - e->time = _ecore_xcb_event_last_time; - ecore_event_add(ECORE_X_EVENT_WINDOW_DELETE_REQUEST, e, NULL, NULL); + 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) && - /* Ignore move and resize with keyboard */ - (ev->data.data32[2] < 9)) + (ev->format == 32) && (ev->data.data32[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 = 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); + 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); } - - /* Xdnd Client Message Handling Begin */ - /* Message Type: XdndEnter target */ else if (ev->type == ECORE_X_ATOM_XDND_ENTER) { - Ecore_X_Event_Xdnd_Enter *e; - Ecore_X_DND_Target *target; - uint32_t three; - - e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter)); - if (!e) return; - - target = _ecore_x_dnd_target_get(); - target->state = ECORE_X_DND_TARGET_ENTERED; - - target = _ecore_x_dnd_target_get(); - target->source = ev->data.data32[0]; - target->win = ev->window; - target->version = ev->data.data32[1] >> 24; - if (target->version > ECORE_X_DND_VERSION) - { - printf("DND: Requested version %d, we only support up to %d\n", target->version, - ECORE_X_DND_VERSION); - return; - } - - /* FIXME: roud trip, but I don't know how to suppress it */ - if ((three = ev->data.data32[1] & 0x1UL)) - { - /* source supports more than 3 types, fetch property */ - unsigned char *data; - Ecore_X_Atom *types; - int num_ret; - int i; - uint8_t format; - - ecore_x_window_prop_property_get_prefetch(target->source, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM); - ecore_x_window_prop_property_get_fetch(); - format = ecore_x_window_prop_property_get(target->source, - ECORE_X_ATOM_XDND_TYPE_LIST, - ECORE_X_ATOM_ATOM, - 32, - &data, - &num_ret); - if (!format) - { - printf("DND: Could not fetch data type list from source window, aborting.\n"); - return; - } - types = (Ecore_X_Atom *)data; - e->types = calloc(num_ret, sizeof(char *)); - if (e->types) - { - xcb_get_atom_name_cookie_t *cookies; - - cookies = (xcb_get_atom_name_cookie_t *)malloc(sizeof(xcb_get_atom_name_cookie_t) * num_ret); + 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++) - cookies[i] = xcb_get_atom_name_unchecked(_ecore_xcb_conn, types[i]); - for (i = 0; i < num_ret; i++) - { - xcb_get_atom_name_reply_t *reply; - char *name; - - reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookies[i], NULL); - if (reply) - { - name = (char *)malloc(sizeof (char) * (reply->name_len + 1)); - memcpy(name, - xcb_get_atom_name_name(reply), - reply->name_len); - name[reply->name_len] = '\0'; - e->types[i] = name; - free(reply); - } - } - free(cookies); - } - e->num_types = num_ret; - } - else - { - int i = 0; - - e->types = calloc(3, sizeof(char *)); - if (e->types) - { - xcb_get_atom_name_cookie_t cookies[3]; - - for (i = 0; i < 3; i++) - cookies[i] = xcb_get_atom_name_unchecked(_ecore_xcb_conn, ev->data.data32[i + 2]); - for (i = 0; i < 3; 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])) { - xcb_get_atom_name_reply_t *reply; - char *name; - - reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookies[i], NULL); - if (reply && (ev->data.data32[i + 2])) - { - name = (char *)malloc(sizeof (char) * (reply->name_len + 1)); - memcpy(name, - xcb_get_atom_name_name(reply), - reply->name_len); - name[reply->name_len] = '\0'; - e->types[i] = name; - } - if (reply) free(reply); + e->types[i] = + ecore_x_atom_name_get(ev->data.data32[i + 2]); + i++; } - } - e->num_types = 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); + e->win = target->win; + e->source = target->source; + ecore_event_add(ECORE_X_EVENT_XDND_ENTER, e, + _ecore_xcb_event_xdnd_enter_free, NULL); } - - /* Message Type: XdndPosition target */ else if (ev->type == ECORE_X_ATOM_XDND_POSITION) { - Ecore_X_Event_Xdnd_Position *e; - Ecore_X_DND_Target *target; - - target = _ecore_x_dnd_target_get(); - if ((target->source != (Ecore_X_Window)ev->data.data32[0]) || - (target->win != ev->window)) - return; - - target->pos.x = (int16_t)ev->data.data32[2] >> 16; - target->pos.y = (int16_t)ev->data.data32[2] & 0xFFFFUL; - target->action = ev->data.data32[4]; /* Version 2 */ - - target->time = (target->version >= 1) ? - 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); + 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); } - - /* Message Type: XdndStatus source */ else if (ev->type == ECORE_X_ATOM_XDND_STATUS) { - Ecore_X_Event_Xdnd_Status *e; - Ecore_X_DND_Source *source; - - source = _ecore_x_dnd_source_get(); - /* Make sure source/target match */ - if ((source->win != ev->window ) || - (source->dest != 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 = (int16_t)ev->data.data32[2] >> 16; - source->rectangle.y = (int16_t)ev->data.data32[2] & 0xFFFFUL; - source->rectangle.width = (uint16_t)ev->data.data32[3] >> 16; - source->rectangle.height = (uint16_t)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); + 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); } - - /* Message Type: XdndLeave target */ - /* Pretend the whole thing never happened, sort of */ else if (ev->type == ECORE_X_ATOM_XDND_LEAVE) { - Ecore_X_Event_Xdnd_Leave *e; - Ecore_X_DND_Target *target; - - target = _ecore_x_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 = ev->data.data32[0]; - ecore_event_add(ECORE_X_EVENT_XDND_LEAVE, e, NULL, NULL); + 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); } - - /* Message Type: XdndDrop target */ else if (ev->type == ECORE_X_ATOM_XDND_DROP) { - Ecore_X_Event_Xdnd_Drop *e; - Ecore_X_DND_Target *target; - - target = _ecore_x_dnd_target_get(); - /* Match source/target */ - if ((target->source != (Ecore_X_Window)ev->data.data32[0]) || - (target->win != ev->window)) - return; - - target->time = (target->version >= 1) ? - 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); + 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); } - - /* Message Type: XdndFinished source */ else if (ev->type == ECORE_X_ATOM_XDND_FINISHED) { - Ecore_X_Event_Xdnd_Finished *e; - Ecore_X_DND_Source *source; - uint8_t completed = 1; - - source = _ecore_x_dnd_source_get(); - /* Match source/target */ - if ((source->win != ev->window) || - (source->dest != ev->data.data32[0])) - return; - - if ((source->version >= 5) && (ev->data.data32[1] & 0x1UL)) - { - /* Target successfully performed drop action */ - ecore_x_selection_xdnd_clear(); - source->state = ECORE_X_DND_SOURCE_IDLE; - } - else - { - completed = 0; - 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 = 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); + 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; - - e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)); - if (!e) 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_x_netwm_state_get(ev->data.data32[1]); - if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN) - { - xcb_get_atom_name_reply_t *reply; - char *name; - - /* FIXME: round trip */ - reply = xcb_get_atom_name_reply(_ecore_xcb_conn, - xcb_get_atom_name_unchecked(_ecore_xcb_conn, ev->data.data32[1]), - NULL); - if (reply) - { - name = (char *)malloc(sizeof (char) * (reply->name_len + 1)); - memcpy(name, - xcb_get_atom_name_name(reply), - reply->name_len); - name[reply->name_len] = '\0'; - printf("Unknown state: %s\n", name); - free(name); - free(reply); - } - } - e->state[1] = _ecore_x_netwm_state_get(ev->data.data32[2]); - if (e->state[1] == ECORE_X_WINDOW_STATE_UNKNOWN) - { - xcb_get_atom_name_reply_t *reply; - char *name; - - reply = xcb_get_atom_name_reply(_ecore_xcb_conn, - xcb_get_atom_name_unchecked(_ecore_xcb_conn, ev->data.data32[2]), - NULL); - if (reply) - { - name = (char *)malloc(sizeof (char) * (reply->name_len + 1)); - memcpy(name, - xcb_get_atom_name_name(reply), - reply->name_len); - name[reply->name_len] = '\0'; - printf("Unknown state: %s\n", name); - free(name); - } - } - e->source = ev->data.data32[3]; - - ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + 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); } - else if ((ev->type == ECORE_X_ATOM_WM_CHANGE_STATE) - && (ev->format == 32) - && (ev->data.data32[0] == XCB_WM_ICONIC_STATE)) +#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; - - e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)); - if (!e) 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); + 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)) + else if ((ev->type == ECORE_X_ATOM_NET_WM_DESKTOP) && (ev->format == 32)) { - Ecore_X_Event_Desktop_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change)); - if (!e) 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); + 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)) + else if (ev->type == ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS) { - Ecore_X_Event_Frame_Extents_Request *e; + Ecore_X_Event_Frame_Extents_Request *e; - e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request)); - if (!e) return; - e->win = ev->window; - - ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL); + 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)) + 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; - - e = calloc(1, sizeof(Ecore_X_Event_Ping)); - if (!e) 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); + 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)) + (ev->format == 8)) { - _ecore_x_netwm_startup_info_begin(ev->window, (char *)ev->data.data8); + _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)) + else if ((ev->type == ECORE_X_ATOM_NET_STARTUP_INFO) && (ev->format == 8)) { - _ecore_x_netwm_startup_info(ev->window, (char *)ev->data.data8); + _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 == _ecore_xcb_private_window)) + else if ((ev->type == 27777) && (ev->data.data32[0] == 0x7162534) && + (ev->format == 32)) // && (ev->window = _private_window)) { - /* a grab sync marker */ - if (ev->data.data32[1] == 0x10000001) - _ecore_x_window_grab_remove(ev->data.data32[2]); - else if (ev->data.data32[1] == 0x10000002) - _ecore_x_key_grab_remove(ev->data.data32[2]); + 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; - - e = calloc(1, sizeof(Ecore_X_Event_Client_Message)); - if (!e) 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); + 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); } } -void -_ecore_x_event_handle_mapping_notify(xcb_generic_event_t *event __UNUSED__) +static void +_ecore_xcb_event_handle_mapping_notify(xcb_generic_event_t *event) { - /* FIXME: handle this event type */ -} + xcb_mapping_notify_event_t *ev; + Ecore_X_Event_Mapping_Change *e; -void -_ecore_x_event_handle_shape_change(xcb_generic_event_t *event) -{ -#ifdef ECORE_X_SHAPE - 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; - e = calloc(1, sizeof(Ecore_X_Event_Window_Shape)); - if (!e) return; - e->win = ev->affected_window; - e->time = ev->server_time; - ecore_event_add(ECORE_X_EVENT_WINDOW_SHAPE, e, NULL, NULL); -#else - event = NULL; -#endif /* ECORE_X_SHAPE */ -} + ev = (xcb_mapping_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Mapping_Change)))) return; -void -_ecore_x_event_handle_screensaver_notify(xcb_generic_event_t *event) -{ -#ifdef ECORE_X_SCREENSAVER - xcb_screensaver_notify_event_t *ev; - Ecore_X_Event_Screensaver_Notify *e; + _ecore_xcb_keymap_refresh(ev); + _ecore_xcb_modifiers_get(); - ev = (xcb_screensaver_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Screensaver_Notify)); - if (!e) return; - e->win = ev->window; - if (ev->state == XCB_SCREENSAVER_STATE_ON) - e->on = 1; - else - e->on = 0; - e->time = ev->time; - ecore_event_add(ECORE_X_EVENT_SCREENSAVER_NOTIFY, e, NULL, NULL); -#else - event = NULL; -#endif /* ECORE_X_SCREENSAVER */ + 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); } -void -_ecore_x_event_handle_sync_counter(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_damage_notify(xcb_generic_event_t *event) { -#ifdef ECORE_X_SYNC - xcb_sync_counter_notify_event_t *ev; - Ecore_X_Event_Sync_Counter *e; +#ifdef ECORE_XCB_DAMAGE + xcb_damage_notify_event_t *ev; + Ecore_X_Event_Damage *e; +#endif - ev = (xcb_sync_counter_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Sync_Counter)); - if (!e) return; - e->time = ev->timestamp; - ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL); -#else - event = NULL; -#endif /* ECORE_X_SYNC */ -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); -void -_ecore_x_event_handle_sync_alarm(xcb_generic_event_t *event) -{ -#ifdef ECORE_X_SYNC - xcb_sync_alarm_notify_event_t *ev; - Ecore_X_Event_Sync_Alarm *e; + _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; - ev = (xcb_sync_alarm_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Sync_Alarm)); - if (!e) return; + e->level = ev->level; + e->drawable = ev->drawable; + e->damage = ev->damage; e->time = ev->timestamp; - e->alarm = ev->alarm; - ecore_event_add(ECORE_X_EVENT_SYNC_ALARM, e, NULL, NULL); -#else - event = NULL; -#endif /* ECORE_X_SYNC */ + 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 } -/* FIXME: round trip */ -void -_ecore_x_event_handle_randr_change(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_randr_change(xcb_generic_event_t *event) { -#ifdef ECORE_X_RANDR +#ifdef ECORE_XCB_RANDR xcb_randr_screen_change_notify_event_t *ev; - Ecore_X_Event_Screen_Change *e; + 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; - if ((ev->response_type & ~0x80) != XCB_CONFIGURE_NOTIFY) - { - xcb_query_extension_reply_t *rep; - - rep = xcb_query_extension_reply(_ecore_xcb_conn, - xcb_query_extension_unchecked(_ecore_xcb_conn, - strlen("randr"), - "randr"), - NULL); - - if ((!rep) || - (((ev->response_type & ~0x80) - rep->first_event) != XCB_RANDR_SCREEN_CHANGE_NOTIFY)) - printf("ERROR: Can't update RandR config!\n"); - if (rep) - free(rep); - } - - e = calloc(1, sizeof(Ecore_X_Event_Screen_Change)); - if (!e) return; e->win = ev->request_window; e->root = ev->root; - e->width = ev->width; - e->height = ev->height; + 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); -#else - event = NULL; -#endif /* ECORE_X_RANDR */ +#endif } -void -_ecore_x_event_handle_fixes_selection_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_randr_notify(xcb_generic_event_t *event) { -#ifdef ECORE_X_FIXES - /* Nothing here yet */ -#else - event = NULL; -#endif /* ECORE_X_FIXES */ +#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 } -void -_ecore_x_event_handle_damage_notify(xcb_generic_event_t *event) +static void +_ecore_xcb_event_handle_randr_crtc_change(xcb_generic_event_t *event) { -#ifdef ECORE_XCBDAMAGE - xcb_damage_notify_event_t *ev; - Ecore_X_Event_Damage *e; +#ifdef ECORE_XCB_RANDR + xcb_randr_notify_event_t *ev; + Ecore_X_Event_Randr_Crtc_Change *e; +#endif - ev = (xcb_damage_notify_event_t *)event; - e = calloc(1, sizeof(Ecore_X_Event_Damage)); - if (!e) return; +#ifdef ECORE_XCB_RANDR + ev = (xcb_randr_notify_event_t *)event; + if (!(e = calloc(1, sizeof(Ecore_X_Event_Randr_Crtc_Change)))) + return; - e->level = ev->level; - e->drawable = ev->drawable; - e->damage = ev->damage; - /* FIXME: XCB has no 'more' member in xcb_damage_notify_event_t */ -/* e->more = ev->more; */ - 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; + 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_DAMAGE_NOTIFY, e, NULL, NULL); -#else - event = NULL; -#endif /* ECORE_XCBDAMAGE */ + 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_Output_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 index 0a4ec22..d811b54 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_gc.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_gc.c @@ -1,45 +1,173 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" - /** * Creates a new default graphics context associated with the given * drawable. - * @param drawable Drawable to create graphics context with. If @c 0 is - * given instead, the default root window is used. - * @return The new default graphics context. - * - * Creates a new default graphics context associated with @p - * drawable. The graphic context can be used with any destination - * drawable having the same root and depth as @p drawable. Use with - * other drawables results in a BadMatch error. + * @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_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, 0, NULL); + 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. - * - * Destroyes the graphic context @p gc as well as the associated - * storage. */ EAPI void -ecore_x_gc_del(Ecore_X_GC gc) +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 index c5b0113..8dea861 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_icccm.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_icccm.c @@ -1,581 +1,1149 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#include "ecore_xcb_private.h" +#include + +EAPI void +ecore_x_icccm_init(void) +{ +} -/* - * Various ICCCM related functions. +/** + * Sets the WM_COMMAND property for @a win. * - * This is ALL the code involving anything ICCCM related, for both WM and - * client. + * @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; -#include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -#include + 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); +} /** - * @defgroup Ecore_X_ICCCM_Group ICCCM related functions. + * Get the WM_COMMAND property for @a win. + * + * Return the command of a window. String must be free'd when done with. * - * Functions related to ICCCM. + * @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; -static int _ecore_x_icccm_size_hints_get (const void *reply, - Ecore_X_Atom property, - xcb_size_hints_t *hints) -{ - uint32_t s; + 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 (!hints) return 0; + if ((reply->type != ECORE_X_ATOM_STRING) || (reply->format != 8)) + { + free(reply); + return; + } - if (!reply) return 0; - if ((((xcb_get_property_reply_t *)reply)->type != ECORE_X_ATOM_WM_SIZE_HINTS) && - ((((xcb_get_property_reply_t *)reply)->format != 8) || - (((xcb_get_property_reply_t *)reply)->format != 16) || - (((xcb_get_property_reply_t *)reply)->format != 32)) && - (((xcb_get_property_reply_t *)reply)->value_len < 15)) /* OldNumPropSizeElements = 15 (pre-ICCCM) */ - return 0; + len = reply->value_len; + if (len < 1) + { + free(reply); + return; + } - memcpy(hints, - xcb_get_property_value((xcb_get_property_reply_t *)reply), - ((xcb_get_property_reply_t *)reply)->value_len); + data = (char *)xcb_get_property_value(reply); + if (len && (data[len - 1] == '\0')) + len--; - s = (XCB_SIZE_US_POSITION_HINT | XCB_SIZE_US_SIZE_HINT | - XCB_SIZE_P_POSITION_HINT | XCB_SIZE_P_SIZE_HINT | - XCB_SIZE_P_MIN_SIZE_HINT | XCB_SIZE_P_MAX_SIZE_HINT | - XCB_SIZE_P_RESIZE_INC_HINT | XCB_SIZE_P_ASPECT_HINT); + c = 1; + for (cp = (char *)data, i = len; i > 0; cp++, i--) + if (*cp == '\0') c++; - if (((xcb_get_property_reply_t *)reply)->value_len >= 18) /* NumPropSizeElements = 18 (ICCCM version 1) */ - s |= (XCB_SIZE_BASE_SIZE_HINT | XCB_SIZE_P_WIN_GRAVITY_HINT); - else + v = (char **)malloc((c + 1) * sizeof(char *)); + if (!v) { - xcb_size_hints_set_base_size(hints, 0, 0); - xcb_size_hints_set_win_gravity(hints, 0); + free(reply); + return; } - /* FIXME: is it necessary ? */ - /* hints->flags &= s; */ /* get rid of unwanted bits */ - return 1; -} + 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++; + } + } -/** - * Sets the state of a window. - * @param window The window. - * @param state The state. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_state_set(Ecore_X_Window window, - Ecore_X_Window_State_Hint state) -{ - uint32_t c[2]; + if (c < 1) + { + free(reply); + free(v); + return; + } - if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) - c[0] = XCB_WM_WITHDRAWN_STATE; - else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL) - c[0] = XCB_WM_NORMAL_STATE; - else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC) - c[0] = XCB_WM_ICONIC_STATE; - c[1] = 0; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_STATE, ECORE_X_ATOM_WM_STATE, 32, - 2, c); + 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); } -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_state_get_prefetch(Ecore_X_Window window) +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]); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_STATE, - ECORE_X_ATOM_WM_STATE, - 0L, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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; } -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_state_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_state_get_fetch(void) +ecore_x_icccm_title_set(Ecore_X_Window win, + const char *title) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + Ecore_Xcb_Textproperty prop; + char *list[1]; + Eina_Bool ret = EINA_FALSE; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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]); } /** - * Gets the state of a window. - * @param window The window. - * @return The state of the window + * Get a window name & class. + * @param win The window + * @param n The name string + * @param c The class string * - * To use this function, you must call before, and in order, - * ecore_x_icccm_state_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_state_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * Get a window name * class */ -EAPI Ecore_X_Window_State_Hint -ecore_x_icccm_state_get(Ecore_X_Window window __UNUSED__) +EAPI void +ecore_x_icccm_name_class_get(Ecore_X_Window win, + char **name, + char **class) { - xcb_get_property_reply_t *reply; - uint8_t *prop; - Ecore_X_Window_State_Hint hint = ECORE_X_WINDOW_STATE_HINT_NONE; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return hint; + 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; - if ((reply->type == 0) || - (reply->format != 8) || - (reply->value_len != 2)) - return hint; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - prop = (uint8_t *)xcb_get_property_value(reply); - switch (prop[0]) { - case XCB_WM_WITHDRAWN_STATE: - hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; - break; - case XCB_WM_NORMAL_STATE: - hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; - break; - case XCB_WM_ICONIC_STATE: - hint = ECORE_X_WINDOW_STATE_HINT_ICONIC; - break; - default: - hint = ECORE_X_WINDOW_STATE_HINT_NONE; - break; - } + if (name) *name = NULL; + if (class) *class = NULL; - return hint; +#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 } /** - * Sends the ClientMessage event with the DeleteWindow property. - * @param window The window. - * @param time The time. - * @ingroup Ecore_X_ICCCM_Group + * 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_delete_window_send(Ecore_X_Window window, - Ecore_X_Time time) +ecore_x_icccm_name_class_set(Ecore_X_Window win, + const char *name, + const char *class) { - ecore_x_client_message32_send(window, ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_EVENT_MASK_NONE, - ECORE_X_ATOM_WM_DELETE_WINDOW, - time, 0, 0, 0); + 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); } /** - * Sends the ClientMessage event with the TakeFocus property. - * @param window The window. - * @param time The time. - * @ingroup Ecore_X_ICCCM_Group + * 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_take_focus_send(Ecore_X_Window window, - Ecore_X_Time time) +ecore_x_icccm_transient_for_set(Ecore_X_Window win, + Ecore_X_Window forwindow) { - ecore_x_client_message32_send(window, ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_EVENT_MASK_NONE, - ECORE_X_ATOM_WM_TAKE_FOCUS, - time, 0, 0, 0); + 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); } /** - * Sends the ClientMessage event with the SaveYourself property. - * @param window The window. - * @param time The time. - * @ingroup Ecore_X_ICCCM_Group + * Remove the transient_for setting from a window. + * @param win The window */ EAPI void -ecore_x_icccm_save_yourself_send(Ecore_X_Window window, - Ecore_X_Time time) +ecore_x_icccm_transient_for_unset(Ecore_X_Window win) { - ecore_x_client_message32_send(window, ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_EVENT_MASK_NONE, - ECORE_X_ATOM_WM_SAVE_YOURSELF, - time, 0, 0, 0); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_WM_TRANSIENT_FOR); } /** - * Sends the ConfigureNotify event with the StructureNotify property. - * @param window The window. - * @param x The X coordinate. - * @param y The Y coordinate. - * @param width The width. - * @param height The height. - * @ingroup Ecore_X_ICCCM_Group + * 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 void -ecore_x_icccm_move_resize_send(Ecore_X_Window window, - int x, - int y, - int width, - int height) +EAPI Ecore_X_Window +ecore_x_icccm_transient_for_get(Ecore_X_Window win) { - xcb_configure_notify_event_t ev; + Ecore_X_Window forwin = 0; + xcb_get_property_cookie_t cookie; - ev.response_type = XCB_CONFIGURE_NOTIFY | 0x80; - ev.pad0 = 0; - ev.sequence = 0; - ev.event = window; - ev.window = window; - ev.above_sibling = 0; - ev.x = x; - ev.y = y; - ev.width = width; - ev.height = height; - ev.border_width = 0; - ev.override_redirect = 0; - xcb_send_event(_ecore_xcb_conn, 0, window, - XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *)&ev); + 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; } /** - * Sets the hints of a window. - * @param window The window. - * @param accepts_focus AcceptFocus hint - * @param initial_state Initial state flags. - * @param icon_pixmap Icon pixmap. - * @param icon_mask Icon mask. - * @param icon_window Icon window. - * @param window_group Group window. - * @param is_urgent IsUrgent flag. - * @ingroup Ecore_X_ICCCM_Group + * Get the window role. + * @param win The window + * @return The window's role string. */ -EAPI void -ecore_x_icccm_hints_set(Ecore_X_Window window, - int 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, - int is_urgent) +EAPI char * +ecore_x_icccm_window_role_get(Ecore_X_Window win) { - xcb_wm_hints_t *hints; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - hints = xcb_alloc_wm_hints(); - if (!hints) - return; - - 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, window, hints); - free(hints); + return ecore_x_window_prop_string_get(win, ECORE_X_ATOM_WM_WINDOW_ROLE); } -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group +/** + * Set the window role hint. + * @param win The window + * @param role The role string */ EAPI void -ecore_x_icccm_hints_get_prefetch(Ecore_X_Window window) +ecore_x_icccm_window_role_set(Ecore_X_Window win, + const char *role) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_HINTS, - ECORE_X_ATOM_WM_HINTS, - 0L, XCB_NUM_WM_HINTS_ELEMENTS); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_WM_WINDOW_ROLE, role); } -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_hints_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group +/** + * Get the window's client leader. + * @param win The window + * @return The window's client leader window, or 0 if unset */ -EAPI void -ecore_x_icccm_hints_get_fetch(void) +EAPI Ecore_X_Window +ecore_x_icccm_client_leader_get(Ecore_X_Window win) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + Ecore_X_Window leader; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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; } /** - * Gets the hints of a window. - * @param window The window. - * @param accepts_focus AcceptFocus hint - * @param initial_state Initial state flags. - * @param icon_pixmap Icon pixmap. - * @param icon_mask Icon mask. - * @param icon_window Icon window. - * @param window_group Group window. - * @param is_urgent IsUrgent flag. - * @return 1 on success, 0 otherwise. + * Set the window's client leader. + * @param win The window + * @param l The client leader window * - * To use this function, you must call before, and in order, - * ecore_x_icccm_hints_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_hints_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * 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 int -ecore_x_icccm_hints_get(Ecore_X_Window window __UNUSED__, - int *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, - int *is_urgent) +EAPI void +ecore_x_icccm_client_leader_set(Ecore_X_Window win, + Ecore_X_Window leader) { - xcb_wm_hints_t *hints; - xcb_get_property_reply_t *reply; - uint32_t flags; - - if (accepts_focus) - *accepts_focus = 1; - 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 = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if ((reply->type != ECORE_X_ATOM_WM_HINTS) || - (reply->value_len < (XCB_NUM_WM_HINTS_ELEMENTS - 1)) || - (reply->format != 32)) - return 0; + ecore_x_window_prop_window_set(win, ECORE_X_ATOM_WM_CLIENT_LEADER, + &leader, 1); +} - hints = xcb_alloc_wm_hints(); - if (!hints) - return 0; +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; - memcpy(hints, xcb_get_property_value(reply), reply->value_len); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - flags = xcb_wm_hints_get_flags(hints); - if ((flags & XCB_WM_INPUT_HINT) && (accepts_focus)) - { - if (xcb_wm_hints_get_input(hints)) - *accepts_focus = 1; - else - *accepts_focus = 0; - } - if ((flags & XCB_WM_STATE_HINT) && (initial_state)) - { - if (xcb_wm_hints_get_initial_state(hints) == XCB_WM_WITHDRAWN_STATE) - *initial_state = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; - else if (xcb_wm_hints_get_initial_state(hints) == XCB_WM_NORMAL_STATE) - *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; - else if (xcb_wm_hints_get_initial_state(hints) == XCB_WM_ICONIC_STATE) - *initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC; - } - if ((flags & XCB_WM_ICON_PIXMAP_HINT) && (icon_pixmap)) - { - *icon_pixmap = xcb_wm_hints_get_icon_pixmap(hints); - } - if ((flags & XCB_WM_ICON_MASK_HINT) && (icon_mask)) - { - *icon_mask = xcb_wm_hints_get_icon_mask(hints); - } - if ((flags & XCB_WM_ICON_WINDOW_HINT) && (icon_window)) + 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)) { - *icon_window = xcb_wm_hints_get_icon_window(hints); + free(reply); + return hint; } - if ((flags & XCB_WM_WINDOW_GROUP_HINT) && (window_group)) + + prop = (uint8_t *)xcb_get_property_value(reply); +#ifdef OLD_XCB_VERSION + switch (prop[0]) { - if (reply->value_len < XCB_NUM_WM_HINTS_ELEMENTS) - *window_group = 0; - else - *window_group = xcb_wm_hints_get_window_group(hints); + 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; } - if ((flags & XCB_WM_X_URGENCY_HINT) && (is_urgent)) +#else + switch (prop[0]) { - *is_urgent = 1; - } + case XCB_ICCCM_WM_STATE_WITHDRAWN: + hint = ECORE_X_WINDOW_STATE_HINT_WITHDRAWN; + break; - free(hints); + case XCB_ICCCM_WM_STATE_NORMAL: + hint = ECORE_X_WINDOW_STATE_HINT_NORMAL; + break; - return 1; -} + case XCB_ICCCM_WM_STATE_ICONIC: + hint = ECORE_X_WINDOW_STATE_HINT_ICONIC; + break; -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_size_pos_hints_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; + default: + break; + } +#endif - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_NORMAL_HINTS, - ECORE_X_ATOM_WM_SIZE_HINTS, - 0L, 18); - _ecore_xcb_cookie_cache(cookie.sequence); + free(reply); + return hint; } -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_size_pos_hints_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_size_pos_hints_get_fetch(void) +ecore_x_icccm_state_set(Ecore_X_Window win, + Ecore_X_Window_State_Hint state) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; +#ifdef OLD_XCB_VERSION + xcb_wm_hints_t hints; +#else + xcb_icccm_wm_hints_t hints; +#endif - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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 } -/** - * Sets the hints of a window. - * @param window The window. - * @param request_pos Request position flag. - * @param gravity Gravity. - * @param min_w Minimum width. - * @param min_h Minimum height. - * @param max_w Maximum width. - * @param max_h Maximum height. - * @param base_w Base width - * @param base_h Base height - * @param step_x X step coordinate. - * @param step_y Y step coordinate. - * @param min_aspect Minimum aspect ratio. - * @param max_aspect Maximum aspect ratio. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_size_pos_hints_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_size_pos_hints_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_size_pos_hints_set(Ecore_X_Window window, - int 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) +ecore_x_icccm_delete_window_send(Ecore_X_Window win, + Ecore_X_Time t) { - xcb_size_hints_t *hint; - xcb_get_property_reply_t *reply; + 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); +} - hint = xcb_alloc_size_hints(); - if (!hint) - return; +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 - reply = _ecore_xcb_reply_get(); - if (!reply || - (reply->type != ECORE_X_ATOM_WM_SIZE_HINTS) || - ((reply->format != 8) && - (reply->format != 16) && - (reply->format != 32)) || - (reply->value_len < 15)) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - xcb_size_hints_set_flags(hint, 0); - if (request_pos) +#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 { - xcb_size_hints_set_flags(hint, XCB_SIZE_US_POSITION_HINT); + if (hints.input) + *accepts_focus = EINA_TRUE; + else + *accepts_focus = EINA_FALSE; } - if (gravity != ECORE_X_GRAVITY_NW) + +#ifdef OLD_XCB_VERSION + if ((hints.flags & XCB_WM_HINT_STATE) && (initial_state)) { - xcb_size_hints_set_win_gravity(hint, (uint8_t)gravity); + 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 ((min_w > 0) || (min_h > 0)) + + 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)) { - xcb_size_hints_set_min_size(hint, min_w, min_h); + 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 ((max_w > 0) || (max_h > 0)) + + 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) { - xcb_size_hints_set_max_size(hint, max_w, max_h); +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; } - if ((base_w > 0) || (base_h > 0)) + + if (!(tmp = malloc((prop.name_len + 1) * sizeof(char *)))) { - xcb_size_hints_set_base_size(hint, base_w, base_h); +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + return NULL; } - if ((step_x > 1) || (step_y > 1)) + memcpy(tmp, prop.name, sizeof(char *) * prop.name_len); + tmp[prop.name_len] = '\0'; + + if (prop.encoding != ECORE_X_ATOM_UTF8_STRING) { - xcb_size_hints_set_resize_inc(hint, step_x, step_y); + 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); + } } - if ((min_aspect > 0.0) || (max_aspect > 0.0)) + +#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) { - xcb_size_hints_set_aspect(hint, - (int32_t)(min_aspect * 10000), - 10000, - (int32_t)(max_aspect * 10000), - 10000); +#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); } - xcb_set_wm_normal_hints(_ecore_xcb_conn, window, hint); + 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; - free(hint); + 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(); } /** - * Gets the hints of a window. - * @param window The window. - * @param request_pos Request position flag. - * @param gravity Gravity. - * @param min_w Minimum width. - * @param min_h Minimum height. - * @param max_w Maximum width. - * @param max_h Maximum height. - * @param base_w Base width - * @param base_h Base height - * @param step_x X step coordinate. - * @param step_y Y step coordinate. - * @param min_aspect Minimum aspect ratio. - * @param max_aspect M - * @return 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_size_pos_hints_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_size_pos_hints_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * 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 int -ecore_x_icccm_size_pos_hints_get(Ecore_X_Window window __UNUSED__, - int *request_pos, +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, @@ -588,21 +1156,19 @@ ecore_x_icccm_size_pos_hints_get(Ecore_X_Window window __UNUSED__, double *min_aspect, double *max_aspect) { - xcb_size_hints_t *hint; - xcb_get_property_reply_t *reply; - uint32_t flags; - int32_t minw = 0; - int32_t minh = 0; - int32_t maxw = 32767; - int32_t maxh = 32767; - int32_t basew = -1; - int32_t baseh = -1; - int32_t stepx = -1; - int32_t stepy = -1; - double mina = 0.0; - double maxa = 0.0; - - if (request_pos) *request_pos = 0; + 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; @@ -615,1299 +1181,389 @@ ecore_x_icccm_size_pos_hints_get(Ecore_X_Window window __UNUSED__, if (min_aspect) *min_aspect = mina; if (max_aspect) *max_aspect = maxa; - - hint = xcb_alloc_size_hints(); - if (!hint) return 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; - - if (!_ecore_x_icccm_size_hints_get(reply, ECORE_X_ATOM_WM_NORMAL_HINTS, hint)) - return 0; - - flags = xcb_size_hints_get_flags(hint); - if ((flags & XCB_SIZE_US_POSITION_HINT) || (flags & XCB_SIZE_P_POSITION_HINT)) +#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 = 1; + if (request_pos) *request_pos = EINA_TRUE; } - if (flags & XCB_SIZE_P_WIN_GRAVITY_HINT) + +#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 = xcb_size_hints_get_win_gravity(hint); + if (gravity) *gravity = hints.win_gravity; } - if (flags & XCB_SIZE_P_MIN_SIZE_HINT) + +#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 { - xcb_size_hints_get_min_size(hint, &minw, &minh); + minw = hints.min_width; + minh = hints.min_height; } - if (flags & XCB_SIZE_P_MAX_SIZE_HINT) + +#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 { - xcb_size_hints_get_max_size(hint, &maxw, &maxh); - if (maxw < minw) - maxw = minw; - if (maxh < minh) - maxh = minh; + maxw = hints.max_width; + maxh = hints.max_height; + if (maxw < minw) maxw = minw; + if (maxh < minh) maxh = minh; } - if (flags & XCB_SIZE_BASE_SIZE_HINT) + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_BASE_SIZE) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) +#endif { - xcb_size_hints_get_base_size(hint, &basew, &baseh); - if (basew > minw) - minw = basew; - if (baseh > minh) - minh = baseh; + basew = hints.base_width; + baseh = hints.base_height; + if (basew > minw) minw = basew; + if (baseh > minh) minh = baseh; } - if (flags & XCB_SIZE_P_RESIZE_INC_HINT) + +#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 { - xcb_size_hints_get_increase(hint, &stepx, &stepy); - if (stepx < 1) - stepx = 1; - if (stepy < 1) - stepy = 1; + stepx = hints.width_inc; + stepy = hints.height_inc; + if (stepx < 1) stepx = 1; + if (stepy < 1) stepy = 1; } - if (flags & XCB_SIZE_P_ASPECT_HINT) + +#ifdef OLD_XCB_VERSION + if (hints.flags & XCB_SIZE_HINT_P_ASPECT) +#else + if (hints.flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) +#endif { - int32_t min_aspect_num; - int32_t min_aspect_den; - int32_t max_aspect_num; - int32_t max_aspect_den; - - xcb_size_hints_get_min_aspect(hint, &min_aspect_num, &min_aspect_den); - if (min_aspect_den > 0) - mina = ((double)min_aspect_num) / ((double)min_aspect_den); - xcb_size_hints_get_max_aspect(hint, &max_aspect_num, &max_aspect_den); - if (max_aspect_den > 0) - maxa = ((double)max_aspect_num) / ((double)max_aspect_den); + 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; - - free(hint); - - return 1; -} + 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; -/** - * Set the title of a window - * @param window The window. - * @param title The title. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_title_set(Ecore_X_Window window, - const char *title) -{ - /* FIXME: to do: utf8 */ - -/* xprop.value = NULL; */ -/* #ifdef X_HAVE_UTF8_STRING */ -/* list[0] = strdup(t); */ -/* ret = */ -/* Xutf8TextListToTextProperty(_ecore_xcb_conn, list, 1, XUTF8StringStyle, */ -/* &xprop); */ -/* #else */ -/* list[0] = strdup(t); */ -/* ret = */ -/* XmbTextListToTextProperty(_ecore_xcb_conn, list, 1, XStdICCTextStyle, */ -/* &xprop); */ -/* #endif */ - - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_NAME, ECORE_X_ATOM_STRING, 8, - strlen(title), title); + return EINA_TRUE; } -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_title_get_prefetch(Ecore_X_Window window) +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; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_NAME, - XCB_GET_PROPERTY_TYPE_ANY, - 0L, 128); - _ecore_xcb_cookie_cache(cookie.sequence); + 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 } -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_title_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_title_get_fetch(void) +ecore_x_icccm_move_resize_send(Ecore_X_Window win, + int x, + int y, + int w, + int h) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + xcb_configure_notify_event_t ev; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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(); } /** - * Gets the title of a window. - * @param window The window (Unused). - * @return The title of the window + * Get a window client machine string. + * @param win The window + * @return The windows client machine string * - * To use this function, you must call before, and in order, - * ecore_x_icccm_title_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_title_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * Return the client machine of a window. String must be free'd when done with. */ EAPI char * -ecore_x_icccm_title_get(Ecore_X_Window window __UNUSED__) +ecore_x_icccm_client_machine_get(Ecore_X_Window win) { - char *title = NULL; - xcb_get_property_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return NULL; - - if (reply->type == ECORE_X_ATOM_UTF8_STRING) - { - int length; - - /* FIXME: verify the value of length */ - length = (reply->value_len * reply->format) / 8; - title = (char *)malloc((length + 1) * sizeof(char)); - memcpy(title, xcb_get_property_value(reply), length); - title[length] = '\0'; - } - /* not in UTF8, so we convert */ - else + 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) { - /* convert to utf8 */ - - /* FIXME: to do... */ - -/* #ifdef X_HAVE_UTF8_STRING */ -/* ret = Xutf8TextPropertyToTextList(_ecore_xcb_conn, &xprop, */ -/* &list, &num); */ -/* #else */ -/* ret = XmbTextPropertyToTextList(_ecore_xcb_conn, &xprop, */ -/* &list, &num); */ -/* #endif */ - -/* 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); */ +#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'; - return title; +#ifdef OLD_XCB_VERSION + xcb_get_text_property_reply_wipe(&prop); +#else + xcb_icccm_get_text_property_reply_wipe(&prop); +#endif + + return tmp; } -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_protocol_get_prefetch(Ecore_X_Window window) +ecore_x_icccm_take_focus_send(Ecore_X_Window win, + Ecore_X_Time t) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_ATOM_ATOM, 0, 1000000L); - _ecore_xcb_cookie_cache(cookie.sequence); + 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); } -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_protocol_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ EAPI void -ecore_x_icccm_protocol_get_fetch(void) +ecore_x_icccm_save_yourself_send(Ecore_X_Window win, + Ecore_X_Time t) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Set or unset a wm protocol property. - * @param window The Window - * @param protocol The protocol to enable/disable - * @param on On/Off - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_protocol_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_protocol_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_protocol_set(Ecore_X_Window window, - Ecore_X_WM_Protocol protocol, - int on) -{ - xcb_get_property_reply_t *reply; - Ecore_X_Atom *protos = NULL; - Ecore_X_Atom proto; - uint32_t protos_count = 0; - uint8_t already_set = 0; - - /* Check for invalid values */ - if (protocol >= ECORE_X_WM_PROTOCOL_NUM) - return; - - proto = _ecore_xcb_atoms_wm_protocols[protocol]; - - reply = _ecore_xcb_reply_get(); - if (!reply) return; - - if ((reply->type == ECORE_X_ATOM_ATOM) && (reply->format == 32)) - { - uint32_t i; - - protos_count = reply->value_len / sizeof(Ecore_X_Atom); - protos = (Ecore_X_Atom *)xcb_get_property_value(reply); - for (i = 0; i < protos_count; i++) - { - if (protos[i] == proto) - { - already_set = 1; - break; - } - } - } - - if (on) - { - Ecore_X_Atom *new_protos = NULL; - - if (already_set) - return; - new_protos = (Ecore_X_Atom *)malloc((protos_count + 1) * sizeof(Ecore_X_Atom)); - if (!new_protos) - return; - memcpy(new_protos, protos, reply->value_len); - new_protos[protos_count] = proto; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_ATOM_ATOM, 32, - protos_count + 1, new_protos); - free(new_protos); - } - else - { - uint32_t i; - - if (!already_set) - return; - for (i = 0; i < protos_count; i++) - { - if (protos[i] == proto) - { - uint32_t j; - - for (j = i + 1; j < protos_count; j++) - protos[j - 1] = protos[j]; - if (protos_count > 1) - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_PROTOCOLS, - ECORE_X_ATOM_ATOM, 32, - protos_count - 1, protos); - else - xcb_delete_property(_ecore_xcb_conn, window, - ECORE_X_ATOM_WM_PROTOCOLS); - return; - } - } - } -} - -/** - * Determines whether a protocol is set for a window. - * @param window The Window (Unused). - * @param protocol The protocol to query. - * @return 1 if the protocol is set, else 0. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_protocol_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_protocol_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI int -ecore_x_icccm_protocol_isset(Ecore_X_Window window __UNUSED__, - Ecore_X_WM_Protocol protocol) -{ - xcb_get_property_reply_t *reply; - Ecore_X_Atom *protos = NULL; - Ecore_X_Atom proto; - uint32_t i; - uint8_t ret = 0; - - /* check for invalid values */ - if (protocol >= ECORE_X_WM_PROTOCOL_NUM) - return 0; - - proto = _ecore_xcb_atoms_wm_protocols[protocol]; - - reply = _ecore_xcb_reply_get(); - if (!reply || (reply->type != ECORE_X_ATOM_ATOM) || (reply->format != 32)) - { - return 0; - } - - protos = (Ecore_X_Atom *)xcb_get_property_value(reply); - for (i = 0; i < reply->value_len; i++) - if (protos[i] == proto) - { - ret = 1; - break; - } - - return ret; -} - -/** - * Set a window name & class. - * @param window The window - * @param name The name string - * @param class The class string - * - * Set the name and class of @p window to respectively @p name and @p class. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_name_class_set(Ecore_X_Window window, - const char *name, - const char *class) -{ - char *class_string; - char *s; - int length_name; - int length_class; - - 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, window, - ECORE_X_ATOM_WM_CLASS, ECORE_X_ATOM_STRING, 8, - length_name + length_class + 2, (void *)class_string); - free(class_string); -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_name_class_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_CLASS, - ECORE_X_ATOM_STRING, - 0, 2048L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_name_class_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_name_class_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get a window name and class. - * @param window The window (Unused). - * @param name The name string. - * @param class The class string. - * - * Store the name and class of @p window into respectively @p name and - * @p class. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_name_class_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_name_class_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_name_class_get(Ecore_X_Window window __UNUSED__, - char **name, - char **class) -{ - xcb_get_property_reply_t *reply; - void *data; - char *n = NULL; - char *c = NULL; - int length; - int length_name; - int length_class; - - - if (name) *name = NULL; - if (class) *class = NULL; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return; - - if ((reply->type != ECORE_X_ATOM_STRING) || - (reply->format != 8)) - return; - - length = reply->value_len; - data = xcb_get_property_value(reply); - /* data contains the name string and the class string */ - /* separated by the NULL character. data is not NULL-terminated */ - length_name = strlen(data); - n = (char *)malloc(sizeof(char) * (length_name + 1)); - if (!n) - return; - length_class = length - length_name - 1; - c = (char *)malloc(sizeof(char) * (length_class + 1)); - if (!c) - { - free(n); - return; - } - - memcpy(n, data, length_name); - n[length_name] = '\0'; - length_class = length - length_name - 1; - data += length_name + 1; - memcpy(c, data, length_class); - c[length_class] = '\0'; - - if (name) - *name = n; - if (class) - *class = c; -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_client_machine_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_WM_CLIENT_MACHINE, - XCB_GET_PROPERTY_TYPE_ANY, - 0L, 1000000L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_client_machine_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_client_machine_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get a window client machine string. - * @param window The window - * @return The windows client machine string - * - * Return the client machine of a window. String must be free'd when done with. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_client_machine_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_client_machine_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI char * -ecore_x_icccm_client_machine_get(Ecore_X_Window window) -{ - char *name; - - name = ecore_x_window_prop_string_get(window, ECORE_X_ATOM_WM_CLIENT_MACHINE); - return name; -} - -/** - * Sets the WM_COMMAND property for @a win. - * - * @param window The window. - * @param argc Number of arguments. - * @param argv Arguments. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_command_set(Ecore_X_Window window, - int argc, - char **argv) -{ - void *buf; - char *b; - int nbytes; - int i; - - for (i = 0, nbytes = 0; i < argc; 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, window, - ECORE_X_ATOM_WM_COMMAND, ECORE_X_ATOM_STRING, 8, - nbytes, buf); - free(buf); -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_command_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_COMMAND, - XCB_GET_PROPERTY_TYPE_ANY, - 0L, 1000000L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_command_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_command_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the WM_COMMAND property for a window. - * - * @param win The window. - * @param argc Number of arguments. - * @param argv Arguments. - * - * Return the command of @p window and store it in @p argv. @p argc - * contains the number of arguments. String must be free'd when done with. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_command_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_command_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_command_get(Ecore_X_Window window __UNUSED__, - int *argc, - char ***argv) -{ - xcb_get_property_reply_t *reply; - char **v; - char *data; - char *cp; - char *start; - uint32_t value_len; - int c; - int i; - int j; - - if (argc) *argc = 0; - if (argv) *argv = NULL; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return; - - if ((reply->type != ECORE_X_ATOM_STRING) || - (reply->format != 8)) - return; - - value_len = reply->value_len; - data = (char *)xcb_get_property_value(reply); - if (value_len && (data[value_len - 1] == '\0')) - value_len--; - - c = 1; - for (cp = (char *)data, i = value_len; i > 0; cp++, i--) - { - if (*cp == '\0') c++; - } - v = (char **)malloc((c + 1) * sizeof(char *)); - if (!v) - return; - - start = (char *)malloc((value_len + 1) * sizeof(char)); - if (!start) - { - free(v); - return; - } - - memcpy (start, (char *) data, value_len); - start[value_len] = '\0'; - for (cp = start, i = value_len + 1, j = 0; i > 0; cp++, i--) { - if (*cp == '\0') { - v[j] = start; - start = (cp + 1); - j++; - } - } - - if (c < 1) - { - if (v) - free(v); - return; - } - - if (argc) *argc = c; - if (argv) - { - (*argv) = malloc(c * sizeof(char *)); - if (!*argv) - { - 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(v); -} - -/** - * Set a window icon name. - * @param window The window. - * @param title The icon name string. - * - * Set @p window icon name. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_icon_name_set(Ecore_X_Window window, - const char *title) -{ - /* FIXME: do the UTF8 conversion... */ - -/* #ifdef X_HAVE_UTF8_STRING */ -/* list[0] = strdup(t); */ -/* ret = Xutf8TextListToTextProperty(_ecore_xcb_conn, list, 1, */ -/* XUTF8StringStyle, &xprop); */ -/* #else */ -/* list[0] = strdup(t); */ -/* ret = XmbTextListToTextProperty(_ecore_xcb_conn, list, 1, */ -/* XStdICCTextStyle, &xprop); */ -/* #endif */ - - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_ICON_NAME, ECORE_X_ATOM_WM_ICON_NAME, - 8, strlen(title), title); -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_icon_name_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_ICON_NAME, - XCB_GET_PROPERTY_TYPE_ANY, - 0L, 128L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_icon_name_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_icon_name_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get a window icon name. - * @param window The window. - * @return The windows icon name string. - * - * Return the icon name of @p window. String must be free'd when done with. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_icon_name_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_icon_name_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI char * -ecore_x_icccm_icon_name_get(Ecore_X_Window window __UNUSED__) -{ - xcb_get_property_reply_t *reply; - char *title = NULL; - - reply = _ecore_xcb_reply_get(); - if (!reply) return NULL; - - printf ("[XCB] reply->bytes_afer (should be 0): %d\n", ((xcb_get_property_reply_t *)reply)->bytes_after); - - if (reply->type == ECORE_X_ATOM_UTF8_STRING) - { - int length; - - /* FIXME: verify the value of length */ - length = reply->value_len * reply->format / 8; - title = (char *)malloc((length + 1) * sizeof(char)); - memcpy(title, xcb_get_property_value(reply), length); - title[length] = '\0'; - } - /* not in UTF8, so we convert */ - else - { - /* FIXME: do the UTF8... */ - - /* convert to utf8 */ -/* #ifdef X_HAVE_UTF8_STRING */ -/* ret = Xutf8TextPropertyToTextList(_ecore_xcb_conn, &xprop, */ -/* &list, &num); */ -/* #else */ -/* ret = XmbTextPropertyToTextList(_ecore_xcb_conn, &xprop, */ -/* &list, &num); */ -/* #endif */ - -/* 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 title; -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_colormap_window_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? ((xcb_screen_t *)_ecore_xcb_screen)->root : window, - ECORE_X_ATOM_WM_COLORMAP_WINDOWS, - ECORE_X_ATOM_WINDOW, - 0L, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_colormap_window_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_colormap_window_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} + 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 window The toplevel window - * @param sub_window The subwindow to be added to the colormap windows list - * - * Add @p sub_window to the list of windows that need a different - * colormap installed. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_colormap_window_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_colormap_window_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * @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 window, - Ecore_X_Window sub_window) +ecore_x_icccm_colormap_window_set(Ecore_X_Window win, + Ecore_X_Window subwin) { - void *data = NULL; - xcb_get_property_reply_t *reply; - uint32_t num; + int num = 0, i = 0; + unsigned char *odata = NULL, *data = NULL; + Ecore_X_Window *newset = NULL, *oldset = NULL; - if (window == 0) - window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - reply = _ecore_xcb_reply_get(); - if (!reply || (reply->format != 32) || (reply->value_len == 0)) + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, &odata, &num)) { - data = calloc(1, sizeof(Ecore_X_Window)); - if (!data) - { - if (reply) free(reply); - return; - } + if (!(newset = calloc(1, sizeof(Ecore_X_Window)))) return; + newset[0] = subwin; num = 1; + data = (unsigned char *)newset; } else { - Ecore_X_Window *newset = NULL; - Ecore_X_Window *oldset = NULL; - uint32_t i; - - num = reply->value_len; - data = calloc(num + 1, sizeof(Ecore_X_Window)); - if (!data) - return; - - newset = (Ecore_X_Window *)data; - oldset = (Ecore_X_Window *)xcb_get_property_value(reply); - for (i = 0; i < num; ++i) + if (!(newset = calloc(num + 1, sizeof(Ecore_X_Window)))) return; + oldset = (Ecore_X_Window *)odata; + for (i = 0; i < num; i++) { - if (oldset[i] == sub_window) + if (oldset[i] == subwin) { + if (odata) free(odata); + odata = NULL; free(newset); return; } - newset[i] = oldset[i]; } - - newset[num++] = sub_window; + newset[num++] = subwin; + if (odata) free(odata); + data = (unsigned char *)newset; } - - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_COLORMAP_WINDOWS, - ECORE_X_ATOM_WINDOW, - 32, num, data); - free(data); + 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 window The toplevel window - * @param sub_window The window to be removed from the colormap window list. - * - * Remove @p sub_window from the list of colormap windows. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_colormap_window_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_colormap_window_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group + * @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 window, - Ecore_X_Window sub_window) +ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, + Ecore_X_Window subwin) { - void *data = NULL; - Ecore_X_Window *oldset = NULL; - Ecore_X_Window *newset = NULL; - xcb_get_property_reply_t *reply; - uint32_t num; - uint32_t i; - uint32_t j; - uint32_t k = 0; + int num = 0, i = 0, j = 0, k = 0; + unsigned char *odata = NULL, *data = NULL; + Ecore_X_Window *newset = NULL, *oldset = NULL; - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - reply = _ecore_xcb_reply_get(); - if (!reply || (reply->format != 32) || (reply->value_len == 0)) + if (!ecore_x_window_prop_property_get(win, ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + ECORE_X_ATOM_WINDOW, 32, &odata, &num)) return; - num = reply->value_len; - oldset = (Ecore_X_Window *)xcb_get_property_value(reply); + oldset = (Ecore_X_Window *)odata; for (i = 0; i < num; i++) { - if (oldset[i] == sub_window) - { - if (num == 1) - { - xcb_delete_property(_ecore_xcb_conn, window, - ECORE_X_ATOM_WM_COLORMAP_WINDOWS); - return; - } - else - { - data = calloc(num - 1, sizeof(Ecore_X_Window)); - newset = (Ecore_X_Window *)data; - for (j = 0; j < num; ++j) - if (oldset[j] != sub_window) - newset[k++] = oldset[j]; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_COLORMAP_WINDOWS, - ECORE_X_ATOM_WINDOW, - 32, k, data); - free(newset); - return; - } - } + 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); } -/** - * Specify that a window is transient for another top-level window and should be handled accordingly. - * @param window The transient window - * @param forwindow The toplevel window - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_transient_for_set(Ecore_X_Window window, - Ecore_X_Window forwindow) -{ - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_TRANSIENT_FOR, ECORE_X_ATOM_WINDOW, 32, - 1, (void *)&forwindow); -} - -/** - * Remove the transient_for setting from a window. - * @param window The window. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_transient_for_unset(Ecore_X_Window window) -{ - xcb_delete_property(_ecore_xcb_conn, window, ECORE_X_ATOM_WM_TRANSIENT_FOR); -} - -/* - * Sends the GetProperty request. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_transient_for_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_WM_TRANSIENT_FOR, - ECORE_X_ATOM_WINDOW, - 0L, 1L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/* - * Gets the reply of the GetProperty request sent by ecore_x_icccm_transient_for_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_transient_for_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the window this window is transient for, if any. - * @param window The window to check (Unused). - * @return The window ID of the top-level window, or 0 if the property does not exist. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_transient_for_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_transient_for_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI Ecore_X_Window -ecore_x_icccm_transient_for_get(Ecore_X_Window window __UNUSED__) -{ - xcb_get_property_reply_t *reply; - Ecore_X_Window forwin = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return forwin; - - if ((reply->format != 32) || - (reply->value_len == 0) || - (reply->type != ECORE_X_ATOM_WINDOW)) - return forwin; - - forwin = *(Ecore_X_Window *)xcb_get_property_value(reply); - - return forwin; -} - -/** - * Set the window role hint. - * @param window The window - * @param role The role string. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_window_role_set(Ecore_X_Window window, - const char *role) -{ - ecore_x_window_prop_string_set(window, ECORE_X_ATOM_WM_WINDOW_ROLE, - (char *)role); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_window_role_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_WM_WINDOW_ROLE, XCB_GET_PROPERTY_TYPE_ANY, - 0L, 1000000L); - _ecore_xcb_cookie_cache(cookie.sequence); -} - - -/** - * Gets the reply of the GetProperty request sent by ecore_x_icccm_window_role_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_window_role_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the window role. - * @param window The window. - * @return The window's role string. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_window_role_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_window_role_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI char * -ecore_x_icccm_window_role_get(Ecore_X_Window window) -{ - return ecore_x_window_prop_string_get(window, ECORE_X_ATOM_WM_WINDOW_ROLE); -} - -/** - * Set the window's client leader. - * @param window The window - * @param leader 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. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_client_leader_set(Ecore_X_Window window, - Ecore_X_Window leader) -{ - ecore_x_window_prop_window_set(window, ECORE_X_ATOM_WM_CLIENT_LEADER, - &leader, 1); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_client_leader_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window, - ECORE_X_ATOM_WM_CLIENT_LEADER, - ECORE_X_ATOM_WINDOW, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); -} - - -/** - * Gets the reply of the GetProperty request sent by ecore_x_icccm_client_leader_get_prefetch(). - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_client_leader_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the window's client leader. - * @param window The window - * @return The window's client leader window, or 0 if unset. - * - * To use this function, you must call before, and in order, - * ecore_x_icccm_client_leader_get_prefetch(), which sends the GetProperty request, - * then ecore_x_icccm_client_leader_get_fetch(), which gets the reply. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI Ecore_X_Window -ecore_x_icccm_client_leader_get(Ecore_X_Window window) -{ - Ecore_X_Window leader; - - if (ecore_x_window_prop_window_get(window, ECORE_X_ATOM_WM_CLIENT_LEADER, - &leader, 1) > 0) - return leader; - - return 0; -} - -/** - * Send the ClientMessage event with the ChangeState property. - * @param window The window. - * @param root The root window. - * @ingroup Ecore_X_ICCCM_Group - */ -EAPI void -ecore_x_icccm_iconic_request_send(Ecore_X_Window window, - Ecore_X_Window root) -{ - xcb_client_message_event_t ev; - - if (!window) return; - if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - /* send_event is bit 7 (0x80) of response_type */ - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.sequence = 0; - ev.window = window; - ev.type = ECORE_X_ATOM_WM_CHANGE_STATE; - ev.data.data32[0] = XCB_WM_ICONIC_STATE; - - xcb_send_event(_ecore_xcb_conn, 0, root, - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&ev); -} - -/* 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/xcb/ecore_xcb_image.c b/src/lib/ecore_x/xcb/ecore_xcb_image.c new file mode 100644 index 0000000..8e22110 --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_image.c @@ -0,0 +1,738 @@ +#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_MSB_FIRST) return EINA_TRUE; +#else + if (im->xim->byte_order == XCB_IMAGE_ORDER_LSB_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 index f96c4cf..6c95331 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_mwm.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_mwm.c @@ -1,24 +1,10 @@ -/* - * Various MWM related functions. - * - * This is ALL the code involving anything MWM related. for both WM and - * client. - */ - #include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" +//#include "Ecore_X_Atoms.h" - -/** - * @defgroup Ecore_X_MWM_Group MWM related functions. - * - * Functions related to MWM. - */ - -#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) +#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 { @@ -27,74 +13,64 @@ typedef struct _mwmhints uint32_t decorations; int32_t inputmode; uint32_t status; -} -MWMHints; - +} MWMHints; /** - * Sends the GetProperty request. - * @param window Window whose MWM hints are requested. - * @ingroup Ecore_X_MWM_Group + * @defgroup Ecore_X_MWM_Group MWM related functions. + * + * Functions related to MWM. */ -EAPI void -ecore_x_mwm_hints_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - ECORE_X_ATOM_MOTIF_WM_HINTS, - ECORE_X_ATOM_MOTIF_WM_HINTS, - 0, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); -} - /** - * Gets the reply of the GetProperty request sent by ecore_x_mwm_hints_get_prefetch(). + * 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_hints_get_fetch(void) +ecore_x_mwm_borderless_set(Ecore_X_Window win, + Eina_Bool borderless) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + uint32_t data[5] = { 0, 0, 0, 0, 0 }; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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); } -/** - * To document. - * @param window Unused. - * @param fhint To document. - * @param dhint To document. - * @param ihint To document. - * @return 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_mwm_hints_get_prefetch(), which sends the GetProperty request, - * then ecore_x_mwm_hints_get_fetch(), which gets the reply. - * @ingroup Ecore_X_MWM_Group - */ -EAPI int -ecore_x_mwm_hints_get(Ecore_X_Window window __UNUSED__, - Ecore_X_MWM_Hint_Func *fhint, - Ecore_X_MWM_Hint_Decor *dhint, - Ecore_X_MWM_Hint_Input *ihint) +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) { - MWMHints *mwmhints = NULL; - int ret = 0; + xcb_get_property_cookie_t cookie; xcb_get_property_reply_t *reply; + MWMHints *mwmhints = NULL; + int ret = EINA_FALSE; - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if ((reply->format != 32) || - (reply->value_len == 0)) - return 0; + 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) @@ -120,30 +96,9 @@ ecore_x_mwm_hints_get(Ecore_X_Window window __UNUSED__, else *ihint = ECORE_X_MWM_HINT_INPUT_MODELESS; } - ret = 1; + ret = EINA_TRUE; } - + free(reply); return ret; } -/** - * Sets the borderless flag of a window using MWM. - * @param window The window. - * @param borderless The borderless flag. - * @ingroup Ecore_X_MWM_Group - */ -EAPI void -ecore_x_mwm_borderless_set(Ecore_X_Window window, - int borderless) -{ - uint32_t data[5] = {0, 0, 0, 0, 0}; - - data[0] = 2; /* just set the decorations hint! */ - data[2] = !borderless; - - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_MOTIF_WM_HINTS, ECORE_X_ATOM_MOTIF_WM_HINTS, - 32, 5, data); -} - diff --git a/src/lib/ecore_x/xcb/ecore_xcb_netwm.c b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c index 13026b1..954e663 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_netwm.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_netwm.c @@ -1,323 +1,307 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#include "ecore_xcb_private.h" -/* - * _NET_WM... aka Extended Window Manager Hint (EWMH) functions. - */ +/* 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); -#include "Ecore_Data.h" -#include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" +/* 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__); -/** - * @defgroup Ecore_X_NetWM_Group Extended Window Manager Hint (EWMH) functions - * - * Functions related to the Extended Window Manager Hint (EWMH). - */ +// _startup_info = +// eina_hash_string_superfast_new(_ecore_xcb_netwm_startup_info_free); +} +EAPI void +ecore_x_netwm_shutdown(void) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); -typedef struct _Ecore_X_Startup_Info Ecore_X_Startup_Info; +// if (_startup_info) eina_hash_free(_startup_info); +// _startup_info = NULL; +} -struct _Ecore_X_Startup_Info +EAPI Eina_Bool +ecore_x_netwm_pid_get(Ecore_X_Window win, + int *pid) { - Ecore_X_Window win; + uint32_t tmp; - int init; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - int buffer_size; - char *buffer; + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_PID, &tmp, 1)) + return EINA_FALSE; - int length; + if (pid) *pid = tmp; - /* 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; -}; + return EINA_TRUE; +} -#if 0 -static void _ecore_x_window_prop_string_utf8_get_prefetch(Ecore_X_Window window, Ecore_X_Atom atom); -static void _ecore_x_window_prop_string_utf8_get_fetch(void); -#endif -static void _ecore_x_window_prop_string_utf8_set(Ecore_X_Window window, Ecore_X_Atom atom, const char *str); -static char *_ecore_x_window_prop_string_utf8_get(Ecore_X_Window window, 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 -static void _ecore_x_netwm_startup_info_free(void *data); - -/* - * Local variables - */ - -static Ecore_Hash *startup_info = NULL; - -/** - * Initialize the NetWM module - */ EAPI void -ecore_x_netwm_init(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) { - startup_info = ecore_hash_new(ecore_direct_hash, ecore_direct_compare); - if (startup_info) + 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) { - ecore_hash_free_value_cb_set(startup_info, _ecore_x_netwm_startup_info_free); + 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; } -/** - * Shutdown the NetWM module - */ EAPI void -ecore_x_netwm_shutdown(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) { - if (startup_info) - ecore_hash_destroy(startup_info); - startup_info = NULL; -} - -/** - * Set the _NET_SUPPORTING_WM_CHECK property. - * @param root The root window. - * @param check The child window. - * @param wm_name The name of the Window Manager. - * - * Set the _NET_SUPPORTING_WM_CHECK property on the @p root window to be - * the ID of the child window @p check created by the Window Manager. - * @p check also have the _NET_WM_NAME property set to the name - * @p wm_name of the Window Manager. - * - * The Window MUST call that function to indicate that a compliant - * window manager is active. - * @ingroup Ecore_X_NetWM_Group - */ + 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) -{ - ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, &check, 1); - 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); -} - -/** - * Set the _NET_SUPPORTED property. - * @param root The root window. - * @param supported The supported hints. - * @param num The number of hints. - * - * Set the _NET_SUPPORTED property on the @p root window. The hints - * that the Window Manager supports are stored in @p supported. - * - * The Window Manager MUST set this property to indicate which hints - * it supports. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_supported_set(Ecore_X_Window root, - Ecore_X_Atom *supported, - int num) + const char *wm_name) { - ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED, supported, num); + 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); } -/** - * Sends the GetProperty request. - * @param root The root window - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_supported_get_prefetch(Ecore_X_Window root) +ecore_x_netwm_supported_set(Ecore_X_Window root, + Ecore_X_Atom *supported, + int num) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, root, - ECORE_X_ATOM_NET_SUPPORTED, ECORE_X_ATOM_ATOM, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED, + supported, num); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_supported_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_supported_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the hints supported by the Window Manager. - * @param root The root window. - * @param supported The supported hints. - * @param num The number of atoms. - * @return 1 on success, 0 otherwise. - * - * Get the hints supported by the Window Manager. @p root is the root - * window. The hints are stored in @p supported. The number of hints - * is stored in @p num. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_supported_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_supported_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int +EAPI Eina_Bool ecore_x_netwm_supported_get(Ecore_X_Window root, Ecore_X_Atom **supported, int *num) { - int num_ret; + int num_ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (num) *num = 0UL; + if (num) *num = 0; if (supported) *supported = NULL; - num_ret = ecore_x_window_prop_xid_list_get(root, - ECORE_X_ATOM_NET_SUPPORTED, - ECORE_X_ATOM_ATOM, - supported); - if (num_ret <= 0) - return 0; + 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; - if (num) *num = (uint32_t)num_ret; - return 1; + return EINA_TRUE; } -/** - * Set the _NET_NUMBER_OF_DESKTOPS property. - * @param root The root window. - * @param n_desks The number of desktops. - * - * Set the number of desktops @p n_desks of the Window Manager by - * sending the _NET_NUMBER_OF_DESKTOPS to the @p root window. - * - * The Window Manager SHOULD set and update this property to indicate - * the number of virtual desktops. A Pager can request a change in the - * number of desktops by using that function. - * @ingroup Ecore_X_NetWM_Group - */ 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); -} - -/** - * Set the _NET_VIRTUAL_ROOTS property. - * @param root The root window. - * @param vroots The virtual root windows. - * @param n_desks The number of desks. - * - * Set the number of virtual desktops by sending the - * _NET_VIRTUAL_ROOTS property to the @p root window. @p vroots is an - * array of window and @p n_desks is the number of windows. - * - * A Window Manager that implements virtual desktops by reparent - * client windows to a child of the root window MUST use that - * function. - * @ingroup Ecore_X_NetWM_Group - */ + &n_desks, 1); +} + EAPI void ecore_x_netwm_desk_roots_set(Ecore_X_Window root, - Ecore_X_Window *vroots, + Ecore_X_Window *vroots, unsigned int n_desks) { - ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_VIRTUAL_ROOTS, vroots, n_desks); -} - -/** - * Set the _NET_DESKTOP_NAMES property. - * @param root The root window. - * @param names The names of the virtual desktops. - * @param n_desks The number of virtual desktops. - * - * Set the name of each virtual desktop by sending the - * _NET_DESKTOP_NAMES to the @p root window. @p names are the names of - * the virtual desktops and @p n_desks is the number of virtual - * desktops. - * - * A Pager MAY use that function. @p n_desks may be different from the - * one passed to ecore_x_netwm_desk_count_set(). If it less or equal, - * then the desktops with high numbers are unnamed. If it is larger, - * then the excess names are considered to be reserved in case the - * number of desktops is increased. - * @ingroup Ecore_X_NetWM_Group - */ + 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, + const char **names, unsigned int n_desks) { - char ss[32]; - char *buf; + char ss[32], *buf = NULL, *t = NULL; const char *s; - uint32_t i; - uint32_t len; - uint32_t l; + uint32_t len = 0, i, l; - buf = NULL; - len = 0; + 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; - buf = realloc(buf, len + l); - memcpy(buf + len, s, l); - len += l; + 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_ATOM_UTF8_STRING, 8, len, (const void *)buf); +// ecore_x_flush(); free(buf); } -/** - * Set the _NET_DESKTOP_GEOMETRY property. - * @param root The root window. - * @param width The width of the desktop. - * @param height The height of the desktop. - * - * Set the common @p width and @p height of all desktops by sending - * the _NET_DESKTOP_GEOMETRY to the @p root window. - * - * This size is equal to the screen size if the Window Manager doesn't - * support large desktops, otherwise it's equal to the virtual size of - * the desktop. The Window Manager SHOULD set this property. A Pager - * can request a change in the desktop geometry by using this - * function. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void ecore_x_netwm_desk_size_set(Ecore_X_Window root, unsigned int width, @@ -325,105 +309,25 @@ ecore_x_netwm_desk_size_set(Ecore_X_Window root, { 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, + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_DESKTOP_GEOMETRY, size, 2); } -/** - * Set the _NET_DESKTOP_VIEWPORT property. - * @param root The root window. - * @param origins An array of paris of coordiantes. - * @param n_desks The number of virtual desktops. - * - * Set the top left corner of each desktop's viewport by sending the - * _NET_DESKTOP_VIEWPORT property to the @p root window. @p origins - * contains each pair of X coordinate and Y coordinate of the top left - * corner of each desktop's viewport. - * - * If the Window Manager does not support large desktops, the - * coordinates MUST be (0,0). A Pager can request to change the - * viewport for the current desktop by using this function. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, unsigned int *origins, unsigned int n_desks) { - ecore_x_window_prop_card32_set(root, - ECORE_X_ATOM_NET_DESKTOP_VIEWPORT, - origins, 2 * n_desks); -} - -/** - * Set the _NET_DESKTOP_LAYOUT property. - * @param root The root window. - * @param orientation - * @param columns - * @param rows - * @param starting_corner - * - * Set the layout of virtual desktops relative to each other by - * sending the _NET_DESKTOP_LAYOUT to the @p root window. - * @p orientation defines the orientation of the virtual desktop. 0 - * means horizontal layout, 1 means vertical layout. @p columns is - * the number of desktops in the X direction and @p rows is the number - * in the Y direction. @p starting_corner is the corner containing the - * first desktop. The values for @p starting_corner are 0 (top-left), - * 1 (top-right), 2 (bottom-right) and 3 (bottom-left). - * - * When the orientation is horizontal the desktops are laid out in - * rows, with the first desktop in the specified starting corner. So a - * layout with four columns and three rows starting in - * the top-left corner looks like this: - * - * +--+--+--+--+ - * | 0| 1| 2| 3| - * +--+--+--+--+ - * | 4| 5| 6| 7| - * +--+--+--+--+ - * | 8| 9|10|11| - * +--+--+--+--+ - * - * With @p starting_corner being bottom-right, it looks like this: - * - * +--+--+--+--+ - * |11|10| 9| 8| - * +--+--+--+--+ - * | 7| 6| 5| 4| - * +--+--+--+--+ - * | 3| 2| 1| 0| - * +--+--+--+--+ - * - * When the orientation is vertical the layout with four columns and - * three rows starting in the top-left corner looks like: - * - * +--+--+--+--+ - * | 0| 3| 6| 9| - * +--+--+--+--+ - * | 1| 4| 7|10| - * +--+--+--+--+ - * | 2| 5| 8|11| - * +--+--+--+--+ - * - * With @p starting_corner being top-right, it looks like: - * - * +--+--+--+--+ - * | 9| 6| 3| 0| - * +--+--+--+--+ - * |10| 7| 4| 1| - * +--+--+--+--+ - * |11| 8| 5| 2| - * +--+--+--+--+ - * - * This function MUST be used by a Pager and NOT by the Window - * Manager. When using this function, the Pager must own a manager - * selection. - * @ingroup Ecore_X_NetWM_Group - */ + 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, @@ -431,2767 +335,1270 @@ ecore_x_netwm_desk_layout_set(Ecore_X_Window root, int rows, int starting_corner) { - uint32_t layout[4]; + 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); -} - -/** - * Set the _NET_WORKAREA property. - * @param root The root window. - * @param areas An array of areas. - * @param n_desks The number of desks. - * - * Set the work area for each desktop by sending the _NET_WORKAREA - * property to the @p root window. An area contains the geometry (X - * and Y coordinates, width and height). These geometries are - * specified relative to the viewport on each desktop and specify an - * area that is completely contained within the viewport. @p areas - * stores these geometries. @p n_desks is the number of geometry to - * set. - * - * This function MUST be set by the Window Manager. It is used by - * desktop applications to place desktop icons appropriately. - * @ingroup Ecore_X_NetWM_Group - */ + 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) { - ecore_x_window_prop_card32_set(root, - ECORE_X_ATOM_NET_WORKAREA, - areas, 4 * n_desks); -} - -/** - * Set the _NET_CURRENT_DESKTOP property. - * @param root The root window. - * @param desk The index of the current desktop. - * - * Set the current desktop by sending the _NET_CURRENT_DESKTOP to the - * @p root window. @p deskmust be an integer number between 0 and the - * number of desks (set by ecore_x_netwm_desk_count_set()) -1. - * - * This function MUST be called by the Window Manager. If a Pagerwants - * to switch to naother desktop, it MUST call that function. - * @ingroup Ecore_X_NetWM_Group - */ + 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) { - ecore_x_window_prop_card32_set(root, - ECORE_X_ATOM_NET_CURRENT_DESKTOP, + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_card32_set(root, ECORE_X_ATOM_NET_CURRENT_DESKTOP, &desk, 1); } -/** - * Set the _NET_SHOWING_DESKTOP property. - * @param root The root window - * @param on 0 to hide the desktop, non 0 to show it. - * - * Set or unset the desktop in a "showing mode" by sending the - * _NET_SHOWING_DESKTOP property to the @p root window. If @p on is 0, - * the windows are hidden and the desktop background is displayed and - * focused. - * - * If a Pager wants to enter or leave the mode, it MUST use this - * function. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, - int on) + Eina_Bool on) { - uint32_t val; + unsigned int val = 0; - val = (on) ? 1 : 0; - ecore_x_window_prop_card32_set(root, - ECORE_X_ATOM_NET_SHOWING_DESKTOP, + 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 - */ - -/** - * Set the _NET_CLIENT_LIST property. - * @param root The root window. - * @param p_clients An array of windows. - * @param n_clients The number of windows. - * - * Map all the X windows managed by the window manager from the oldest - * to the newest by sending the _NET_CLIENT_LIST property to the - * @p root window. The X windows are stored in @p p_clients and their - * number in @p n_clients. - * - * This function SHOULD be called by the Window Manager. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_client_list_set(Ecore_X_Window root, - Ecore_X_Window *p_clients, - unsigned int n_clients) +EAPI int +ecore_x_netwm_startup_id_get(Ecore_X_Window win, + char **id) { - ecore_x_window_prop_window_set(root, - ECORE_X_ATOM_NET_CLIENT_LIST, - p_clients, n_clients); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); -/** - * Set the _NET_CLIENT_LIST_STACKING property. - * @param root The root window. - * @param p_clients An array of windows. - * @param n_clients The number of windows. - * - * Stack all the X windows managed by the window manager from bottom - * to top order by sending the _NET_CLIENT_LIST_STACKING property to the - * @p root window. The X windows are stored in @p p_clients and their - * number in @p n_clients. - * - * This function SHOULD be called by the Window Manager. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, - Ecore_X_Window *p_clients, - unsigned int n_clients) -{ - ecore_x_window_prop_window_set(root, - ECORE_X_ATOM_NET_CLIENT_LIST_STACKING, - p_clients, n_clients); -} + if (id) + { + *id = + ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_STARTUP_ID); + } -/** - * Set the _NET_ACTIVE_WINDOW property. - * @param root The root window. - * @param window The widow to activate. - * - * Activate @p window by sending the _NET_ACTIVE_WINDOW property to - * the @p root window. - * - * If a Client wants to activate another window, it MUST call this - * function. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_client_active_set(Ecore_X_Window root, - Ecore_X_Window window) -{ - ecore_x_window_prop_window_set(root, - ECORE_X_ATOM_NET_ACTIVE_WINDOW, - &window, 1); -} - -/** - * Set the _NET_WM_NAME property. - * @param window The widow to activate. - * @param name The title name of the window. - * - * Set the title name of @p window to @p name by sending the - * _NET_WM_NAME property to @p window. - * - * The Client SHOULD set the title of @p window in UTF-8 encoding. If - * set, the Window Manager should use this in preference to WM_NAME. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_name_set(Ecore_X_Window window, - const char *name) -{ - _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_NAME, name); + return 1; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_name_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_startup_id_set(Ecore_X_Window win, + const char *id) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_NAME, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_STARTUP_ID, id); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_name_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_name_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the title of a window. - * @param window The window. - * @param name The title name. - * @return Returns always 1. - * - * Retrieve the title name of @p window and store it in @p name. The - * function returns always 1. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_name_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_name_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_name_get(Ecore_X_Window window, - char **name) +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) { - if (name) - *name = _ecore_x_window_prop_string_utf8_get(window, ECORE_X_ATOM_NET_WM_NAME); - return 1; + 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(); } -/** - * Set the _NET_STARTUP_ID property. - * @param window The window. - * @param id The ID name. - * - * Set the ID @p id used for the startup sequence by sending the - * property _NET_STARTUP_ID to @p window. The ID name should be - * encoded in UTF-8. - * - * If a new value for the property is set, the Window Manager - * should update the window's status accordingly (update its virtual - * desktop, etc.). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_startup_id_set(Ecore_X_Window window, - const char *id) +ecore_x_netwm_window_state_set(Ecore_X_Window win, + Ecore_X_Window_State *state, + unsigned int num) { - _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_STARTUP_ID, id); + 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); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_startup_id_get_prefetch(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_netwm_window_state_get(Ecore_X_Window win, + Ecore_X_Window_State **state, + unsigned int *num) { - xcb_get_property_cookie_t cookie; + 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); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_STARTUP_ID, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + return EINA_TRUE; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_startup_id_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_startup_id_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the startup ID name of a window. - * @param window The window - * @param id The ID name - * @return Return always 1. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_startup_id_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_startup_id_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_startup_id_get(Ecore_X_Window window, - char **id) +ecore_x_netwm_client_active_set(Ecore_X_Window root, + Ecore_X_Window win) { - if (id) - *id = _ecore_x_window_prop_string_utf8_get(window, ECORE_X_ATOM_NET_STARTUP_ID); - return 1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, + ECORE_X_ATOM_NET_ACTIVE_WINDOW, &win, 1); } -/** - * Set the _NET_WM_VISIBLE_NAME property. - * @param window The widow to activate. - * @param name The title name of the window. - * - * Set the title name of @p window to @p name by sending the - * _NET_WM_VISIBLE_NAME property to @p window, when the Window Manager - * displays a window name other than by calling - * ecore_x_netwm_name_set(). - * - * The Client SHOULD set the title of @p window in UTF-8 - * encoding. This function is used for displaying title windows like - * [xterm1], [xterm2], ... thereby allowing Pagers to display the same - * title as the Window Manager. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_visible_name_set(Ecore_X_Window window, - const char *name) +ecore_x_netwm_client_active_request(Ecore_X_Window root, + Ecore_X_Window win, + int type, + Ecore_X_Window current_win) { - _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_VISIBLE_NAME, - name); + 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(); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_visible_name_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_client_list_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_VISIBLE_NAME, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST, + p_clients, n_clients); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_visible_name_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_visible_name_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the visible title of a window. - * @param window The window. - * @param name The title name. - * @return Returns always 1. - * - * Retrieve the visible title name of @p window and store it in @p name. The - * function returns always 1. - * @param window The window - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_visible_name_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_visible_name_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_visible_name_get(Ecore_X_Window window, - char **name) +ecore_x_netwm_client_list_stacking_set(Ecore_X_Window root, + Ecore_X_Window *p_clients, + unsigned int n_clients) { - if (name) - *name = _ecore_x_window_prop_string_utf8_get(window, - ECORE_X_ATOM_NET_WM_VISIBLE_NAME); - return 1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_CLIENT_LIST_STACKING, + p_clients, n_clients); } -/** - * Set the _NET_WM_ICON_NAME property. - * @param window The widow to activate. - * @param name The icon name of the window. - * - * Set the icon name of @p window to @p name by sending the - * _NET_WM_ICON_NAME property to @p window. - * - * The Client SHOULD set the title of @p window in UTF-8 encoding. If - * set, the Window Manager should use this in preference to WM_ICON_NAME. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_icon_name_set(Ecore_X_Window window, - const char *name) +EAPI Eina_Bool +ecore_x_screen_is_composited(int screen) { - _ecore_x_window_prop_string_utf8_set(window, ECORE_X_ATOM_NET_WM_ICON_NAME, - name); + 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; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icon_name_get_prefetch(Ecore_X_Window window) +ecore_x_screen_is_composited_set(int screen, + Ecore_X_Window win) { - xcb_get_property_cookie_t cookie; + static Ecore_X_Atom atom = XCB_NONE; + char buff[32]; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_ICON_NAME, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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()); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_icon_name_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icon_name_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the icon name of a window. - * @param window The window. - * @param name The icon name. - * @return Returns always 1. - * - * Retrieve the icon name of @p window and store it in @p name. The - * function returns always 1. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_icon_name_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_icon_name_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_icon_name_get(Ecore_X_Window window, - char **name) +ecore_x_netwm_ping_send(Ecore_X_Window win) { - if (name) - *name = _ecore_x_window_prop_string_utf8_get(window, - ECORE_X_ATOM_NET_WM_ICON_NAME); - return 1; -} + xcb_client_message_event_t ev; -/** - * Set the _NET_WM_VISIBLE_ICON_NAME property. - * @param window The widow to activate. - * @param name The title name of the window. - * - * Set the icon name of @p window to @p name by sending the - * _NET_WM_VISIBLE_ICON_NAME property to @p window, when the Window Manager - * displays a icon name other than by calling - * ecore_x_netwm_icon_name_set(). - * - * The Client SHOULD set the icon name in UTF-8 - * encoding. The Window Manager MUST use this function is it display - * an icon name other than with ecore_x_netwm_icon_name_set(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_visible_icon_name_set(Ecore_X_Window window, - const char *name) -{ - _ecore_x_window_prop_string_utf8_set(window, - ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, - name); + 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(); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_visible_icon_name_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_frame_size_set(Ecore_X_Window win, + int fl, + int fr, + int ft, + int fb) { - xcb_get_property_cookie_t cookie; + uint32_t frames[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_visible_icon_name_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_visible_icon_name_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the visible icon name of a window. - * @param window The window. - * @param name The icon name. - * @return Returns always 1. - * - * Retrieve the visible icon name of @p window and store it in - * @p name. The function returns always 1. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_visible_icon_name_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_visible_icon_name_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_visible_icon_name_get(Ecore_X_Window window, - char **name) +EAPI Eina_Bool +ecore_x_netwm_frame_size_get(Ecore_X_Window win, + int *fl, + int *fr, + int *ft, + int *fb) { - if (name) - *name = _ecore_x_window_prop_string_utf8_get(window, - ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME); - return 1; + 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; } -/** - * Set the _NET_WM_DESKTOP property. - * @param window The window. - * @param desk The desktop index. - * - * Set on which desktop the @p window is in by sending the - * _NET_WM_DESKTOP property to @p window. @p desk is the index of - * the desktop, starting from 0. To indicate that the window should - * appear on all desktops, @p desk must be equal to 0xFFFFFFFF. - * - * A Client MAY choose not to set this property, in which case the - * Window Manager SHOULD place it as it wishes. - * - * The Window Manager should honor _NET_WM_DESKTOP whenever a - * withdrawn window requests to be mapped. - * - * A Client can request a change of desktop for a non-withdrawn window - * by sending a _NET_WM_DESKTOP client message to the root window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_desktop_set(Ecore_X_Window window, - unsigned int desk) +ecore_x_netwm_sync_request_send(Ecore_X_Window win, + unsigned int serial) { - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1); + 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(); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_desktop_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_desktop_set(Ecore_X_Window win, + unsigned int desk) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_DESKTOP, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_DESKTOP, &desk, 1); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_desktop_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_desktop_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the visible icon name of a window. - * @param window The window. - * @param desk The desktop index. - * @return 1 on success, 0 otherwise. - * - * Retrieve the desktop index in which @p window is displayed and - * store it in @p desk. If @p desk value is 0xFFFFFFFF, the window - * appears on all desktops. The function returns 1 on success, 0 - * otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_desktop_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_desktop_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_desktop_get(Ecore_X_Window window, - unsigned int *desk) +EAPI Eina_Bool +ecore_x_netwm_desktop_get(Ecore_X_Window win, + unsigned int *desk) { - int ret; - uint32_t tmp; + unsigned int tmp = 0; - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_DESKTOP, - &tmp, 1); + 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 (ret == 1) ? 1 : 0; -} - -/** - * Set the _NET_WM_STRUT property. - * @param window The window - * @param left The number of pixels at the left of the screen. - * @param right The number of pixels at the right of the screen. - * @param top The number of pixels at the top of the screen. - * @param bottom The number of pixels at the bottom of the screen. - * - * Set space at the edje of the screen by sending the _NET_WM_STRUT - * property to @p window if @p window is to reserve that space. - * @p left, @p right, @p top and @p bottom are respectively the number - * of pixels at the left, right, top and bottom of the screen. - * - * This property is deprecated and ecore_x_netwm_strut_partial_set() - * should be used instead. However, Clients MAY set this property in - * addition to _NET_WM_STRUT_PARTIAL to ensure backward compatibility - * with Window Managers supporting older versions of the - * Specification. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_strut_set(Ecore_X_Window window, - int left, - int right, - int top, - int bottom) -{ - uint32_t strut[4]; - strut[0] = left; - strut[1] = right; - strut[2] = top; - strut[3] = bottom; - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_STRUT, strut, 4); + return EINA_TRUE; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_strut_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_desktop_request_send(Ecore_X_Window win, + Ecore_X_Window root, + unsigned int desktop) { - xcb_get_property_cookie_t cookie; + 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)); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_STRUT, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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(); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_strut_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_strut_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/* - * _NET_WM_STRUT is deprecated - */ - -/** - * Get the space at the edje of the screen. - * @param window The window - * @param left The number of pixels at the left of the screen. - * @param right The number of pixels at the right of the screen. - * @param top The number of pixels at the top of the screen. - * @param bottom The number of pixels at the bottom of the screen. - * @return 1 on success, 0 otherwise. - * - * Retrieve the space at the edje of the screen if @p window is to - * reserve such space. The number of pixels at the left, right, top - * and bottom of the screen are respectively stored in @p left, - * @p right, @p top and @p bottom. This function returns 1 on success, - * 0 otherwise. - * - * This property is deprecated. See ecore_x_netwm_strut_set() for more - * informations. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_strut_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_strut_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_strut_get(Ecore_X_Window window, - int *left, - int *right, - int *top, - int *bottom) -{ - uint32_t strut[4]; - int ret = 0; - - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_STRUT, strut, 4); - if (ret != 4) - return 0; - - if (left) *left = strut[0]; - if (right) *right = strut[1]; - if (top) *top = strut[2]; - if (bottom) *bottom = strut[3]; +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; - return 1; + 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); } -/** - * Set the _NET_WM_STRUT_PARTIAL property. - * @param window The window - * @param left The number of pixels at the left of the screen. - * @param right The number of pixels at the right of the screen. - * @param top The number of pixels at the top of the screen. - * @param bottom The number of pixels at the bottom of the screen. - * @param left_start_y The number of pixels. - * @param left_end_y The number of pixels. - * @param right_start_y The number of pixels. - * @param right_end_y The number of pixels. - * @param top_start_x The number of pixels. - * @param top_end_x The number of pixels. - * @param bottom_start_x The number of pixels. - * @param bottom_end_x The number of pixels. - * - * Set space at the edje of the screen by sending the - * _NET_WM_STRUT_PARTIAL property to @p window if @p window is to - * reserve that space. @p left, @p right, @p top and @p bottom are - * respectively the number of pixels at the left, right, top and - * bottom of the screen. - * - * TODO: more description for that function. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_strut_partial_set(Ecore_X_Window window, - 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) +ecore_x_netwm_handled_icons_set(Ecore_X_Window win) { - 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(window, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, strut, 12); + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_strut_partial_get_prefetch(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_netwm_handled_icons_get(Ecore_X_Window win) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, + NULL, 0)) + return EINA_FALSE; + + return EINA_TRUE; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_strut_partial_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_strut_partial_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the space at the edje of the screen of a window. - * @param window The window - * @param left The number of pixels at the left of the screen. - * @param right The number of pixels at the right of the screen. - * @param top The number of pixels at the top of the screen. - * @param bottom The number of pixels at the bottom of the screen. - * @param left_start_y The number of pixels. - * @param left_end_y The number of pixels. - * @param right_start_y The number of pixels. - * @param right_end_y The number of pixels. - * @param top_start_x The number of pixels. - * @param top_end_x The number of pixels. - * @param bottom_start_x The number of pixels. - * @param bottom_end_x The number of pixels. - * - * Retrieve the space at the edje of the screen if @p window is to - * reserve such space. The number of pixels at the left, right, top - * and bottom of the screen are respectively stored in @p left, - * @p right, @p top and @p bottom. This function returns 1 on success, - * 0 otherwise. - * - * TODO: more description for that function. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_strut_partial_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_strut_partial_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ EAPI int -ecore_x_netwm_strut_partial_get(Ecore_X_Window window, - 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) +ecore_x_netwm_icon_name_get(Ecore_X_Window win, + char **name) { - uint32_t strut[12]; - int ret = 0; - - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, strut, 12); - if (ret != 12) - return 0; - - 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]; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + { + *name = + ecore_x_window_prop_string_get(win, ECORE_X_ATOM_NET_WM_ICON_NAME); + } + return 1; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icons_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_icon_name_set(Ecore_X_Window win, + const char *name) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_ICON, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_ICON_NAME, name); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_icons_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icons_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Retrieve hte possible icons of a window. - * @param window The window - * @param icon An array of icons. - * @param num The number of icons. - * @return 1 on success, 0 otherwise. - * - * Retrieve an array of possible icons of @p window. The icons are - * stored in @p icon and their number in @p num. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_icons_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_icons_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_icons_get(Ecore_X_Window window, +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) { - uint32_t *data; - uint32_t *p; - uint32_t *src; - uint32_t icons; - uint32_t len; - uint32_t i; - int num_ret; + int num_ret = 0; + unsigned int i = 0, len = 0, icons = 0; + unsigned int *data, *p, *src; - if (num) *num = 0UL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (num) *num = 0; if (icon) *icon = NULL; - num_ret = ecore_x_window_prop_card32_list_get(window, - ECORE_X_ATOM_NET_WM_ICON, - &data); - if ((num_ret <= 0) || !data) - return 0; + 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) { - free(data); - return 0; + if (data) 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 0; - } - icons++; - - if ((p - data) == num_ret) - p = NULL; + 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 the user doesn't want the icons, return */ if (!icon) { - free(data); - return 1; + if (data) free(data); + return EINA_TRUE; } - /* Allocate memory */ *icon = malloc(icons * sizeof(Ecore_X_Icon)); if (!(*icon)) { - free(data); - return 0; + if (data) free(data); + return EINA_FALSE; } /* Fetch the icons */ p = data; for (i = 0; i < icons; i++) { - uint32_t *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(uint32_t)); - if (!((*icon)[i]).data) - { - while (i) - free(((*icon)[--i]).data); - free(*icon); - free(data); - return 0; - } - - pd = ((*icon)[i]).data; - ps = src; - pe = ps + len; - for (; ps < pe; ps++) - { - uint32_t 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); + 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 1; + if (data) free(data); + return EINA_TRUE; } -/** - * Set the _NET_WM_ICON_GEOMETRY property. - * @param window The window. - * @param x The X coordinate of the icon. - * @param y The Y coordinate of the icon. - * @param width The width of the icon. - * @param height The height of the icon. - * - * Set the geometry of the icon of @p window by sending the - * _NET_WM_ICON_GEOMETRY property to @p window. @p x, @p y, @p width - * and @p height specify respectively the X coordinate, the Y - * coordinate, the width and the height of the icon. - * - * Stand alone tools like a taskbar or an iconbox MAY use this - * function. This functions makes possible for a Window Manager to - * display a nice animation like morphing the window into its icon. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icon_geometry_set(Ecore_X_Window window, +ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, int x, int y, - int width, - int height) + int w, + int h) { - uint32_t geometry[4]; + unsigned int geom[4]; - geometry[0] = (uint32_t)x; - geometry[1] = (uint32_t)y; - geometry[2] = (uint32_t)width; - geometry[3] = (uint32_t)height; - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, geometry, 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); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_icon_geometry_get_prefetch(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_netwm_icon_geometry_get(Ecore_X_Window win, + int *x, + int *y, + int *w, + int *h) { - xcb_get_property_cookie_t cookie; + int ret = 0; + unsigned int geom[4]; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_icon_geometry_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_icon_geometry_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the geometry of an icon. - * @param window The window - * @param x x - * @param x The X coordinate of the icon. - * @param y The Y coordinate of the icon. - * @param width The width of the icon. - * @param height The height of the icon. - * @return 1 on success, 0 othrwise. - * - * Retrieve the geometry of the icon of @p window. The geometry is - * stored in @p x, @p y, @p width and @p height. The function returns - * 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_icon_geometry_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_icon_geometry_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_icon_geometry_get(Ecore_X_Window window, - int *x, - int *y, - int *width, - int *height) +ecore_x_netwm_strut_set(Ecore_X_Window win, + int l, + int r, + int t, + int b) { - uint32_t geometry[4]; - int ret; + unsigned int strut[4]; - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, geometry, 4); - if (ret != 4) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (x) *x = geometry[0]; - if (y) *y = geometry[1]; - if (width) *width = geometry[2]; - if (height) *height = geometry[3]; + 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); +} - return 1; +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; } -/** - * Set the _NET_WM_PID property. - * @param window The window. - * @param pid The process ID. - * - * Set the process ID of the client owning @p window by sending the - * _NET_WM_PID property to @p window. - * - * This function MAY be used by the Window Manager to kill windows - * which do not respond to the _NET_WM_PING protocol. - * - * If _NET_WM_PID is set, the ICCCM-specified property - * WM_CLIENT_MACHINE MUST also be set. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_pid_set(Ecore_X_Window window, - int pid) +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 tmp; + unsigned int strut[12]; - tmp = pid; - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_PID, - &tmp, 1); + 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); } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_pid_get_prefetch(Ecore_X_Window window) +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) { - xcb_get_property_cookie_t cookie; + 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; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_PID, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + 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; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_pid_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_pid_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the process ID of a client window. - * @param window The window. - * @param pid The process ID. - * @return 1 on success, 0 otherwise. - * - * Retrieve the process ID of @p window and store it in @p pid. This - * function returns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_pid_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_pid_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_pid_get(Ecore_X_Window window, - int *pid) +ecore_x_netwm_user_time_set(Ecore_X_Window win, + unsigned int t) { - int ret; - uint32_t tmp; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_PID, - &tmp, 1); - if (pid) *pid = tmp; + ecore_x_window_prop_card32_set(win, ECORE_X_ATOM_NET_WM_USER_TIME, &t, 1); +} - return (ret == 1) ? 1 : 0; -} - -/** - * Set the _NET_WM_HANDLED_ICONS property. - * @param window The window. - * - * Indicate to the Window Manager that it does not need to provide - * icons for the iconified @p window by sending the - * _NET_WM_HANDLED_ICONS property to @p window. - * - * This function can be used by a Pager on one of its own toplevel - * windows (for example if the Client is a taskbar and provides - * buttons for iconified windows). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_handled_icons_set(Ecore_X_Window window) +EAPI Eina_Bool +ecore_x_netwm_user_time_get(Ecore_X_Window win, + unsigned int *t) { - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, - NULL, 0); + 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; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_handled_icons_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_visible_name_set(Ecore_X_Window win, + const char *name) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_HANDLED_ICONS, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_NAME, + name); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_handled_icons_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_handled_icons_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Return wheter the Client handles icons or not. - * @param window The window. - * @return 1 if icons are handled, 0 otherwise. - * - * Return whether the client handles icons or not if @p window is - * iconified. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_handled_icons_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_handled_icons_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ EAPI int -ecore_x_netwm_handled_icons_get(Ecore_X_Window window) -{ - int ret = 0; - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_HANDLED_ICONS, - NULL, 0); - return (ret == 0) ? 1 : 0; -} - -/** - * Set the _NET_WM_USER_TIME property. - * @param window The window. - * @param time The last user activity time in the window. - * - * Set the XServer time at which last user activity in @p window took - * place by sending the _NET_WM_USER_TIME property to @p window. @p - * time contains that XServer time in seconds. - * - * This function allows a Window Manager to alter the focus, stacking, - * and/or placement behavior of windows when they are mapped depending - * on whether the new window was created by a user action or is a - * "pop-up" window activated by a timer or some other event. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_user_time_set(Ecore_X_Window window, - unsigned int time) +ecore_x_netwm_visible_name_get(Ecore_X_Window win, + char **name) { - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_USER_TIME, - &time, 1); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + *name = ecore_x_window_prop_string_get(win, + ECORE_X_ATOM_NET_WM_VISIBLE_NAME); + return 1; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_user_time_get_prefetch(Ecore_X_Window window) +ecore_x_netwm_visible_icon_name_set(Ecore_X_Window win, + const char *name) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_USER_TIME, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + ecore_x_window_prop_string_set(win, ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, + name); } -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_user_time_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_user_time_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the last user activity time in the window. - * @param window The window. - * @param time The returned time. - * @return 1 on success, 0 otherwise. - * - * Return the XServer time at which last user activity in @p window - * took place. The time is stored in @p time. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_user_time_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_user_time_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ EAPI int -ecore_x_netwm_user_time_get(Ecore_X_Window window, - unsigned int *time) +ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, + char **name) { - int ret; - uint32_t tmp; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (name) + { + *name = + ecore_x_window_prop_string_get(win, + ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME); + } - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_USER_TIME, - &tmp, 1); - if (time) *time = tmp; - return (ret == 1) ? 1 : 0; + return 1; } -Ecore_X_Window_State -_ecore_x_netwm_state_get(Ecore_X_Atom a) +EAPI Eina_Bool +ecore_x_netwm_sync_counter_get(Ecore_X_Window win, + Ecore_X_Sync_Counter *counter) { - 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; - } -} - -/** - * Set the _NET_WM_STATE property. - * @param window The window. - * @param state An array of window hints. - * @param num The number of hints. - * - * Set a list of hints describing @p window state by sending the - * _NET_WM_STATE property to @p window. The hints are stored in the - * array @p state. @p num must contain the number of hints. - * - * The Window Manager SHOULD honor _NET_WM_STATE whenever a withdrawn - * window requests to be mapped. A Client wishing to change the state - * of a window MUST send a _NET_WM_STATE client message to the root - * window. The Window Manager MUST keep this property updated to - * reflect the current state of the window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_state_set(Ecore_X_Window window, - Ecore_X_Window_State *state, - unsigned int num) -{ - Ecore_X_Atom *set; - uint32_t i; - - if (!num) - { - ecore_x_window_prop_property_del(window, 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(window, ECORE_X_ATOM_NET_WM_STATE, set, num); - - free(set); -} - -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_state_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_STATE, ECORE_X_ATOM_ATOM, - 0, 0x7fffffff);; - _ecore_xcb_cookie_cache(cookie.sequence); -} - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_state_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_state_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the hints describing the window state. - * @param window The window. - * @param state The returned hins. - * @param num The number of hints. - * @return 1 on success, 0 otherwise. - * - * Retrieve the hints describing @p window state. The state is - * returned in @p state. The nummber of hints is stored in @p - * num. This function returns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_window_state_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_window_state_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_window_state_get(Ecore_X_Window window, - Ecore_X_Window_State **state, - unsigned int *num) -{ - Ecore_X_Atom *atoms; - int num_ret; - int i; - - if (num) *num = 0; - if (state) *state = NULL; - - num_ret = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_STATE, - &atoms); - if (num_ret <= 0) - return 0; - - 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 1; -} - -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 - 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; - default: - return 0; - } -} + unsigned int tmp; -/* - * 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 - */ - -/** - * Set the _NET_WM_WINDOW_TYPE property. - * @param window The window. - * @param type The functional type of the window. - * - * Set the functional @p type of @p window by sending _NET_WM_WINDOW_TYPE - * property to @p window. - * - * This property SHOULD be set by the Client before mapping. This - * property SHOULD be used by the window manager in determining the - * decoration, stacking position and other behavior of the window. The - * Client SHOULD specify window types in order of preference (the first - * being most preferable). - * - * This hint is intended to replace the MOTIF hints. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_type_set(Ecore_X_Window window, - 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(window, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, - &atom, 1); -} + if (!ecore_x_window_prop_card32_get(win, + ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, + &tmp, 1)) + return EINA_FALSE; -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_type_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; + if (counter) *counter = tmp; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_WINDOW_TYPE, ECORE_X_ATOM_ATOM, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + return EINA_TRUE; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_type_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_window_type_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/* FIXME: Maybe return 0 on some conditions? */ - -/** - * Get the functional type of a window. - * @param window The window. - * @param type The function type of the window. - * @return 1 on success, 0 otherwise. - * - * Retrieve the functional type of @p window. The type is stored in - * @p type. This function returns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_window_type_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_window_type_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_window_type_get(Ecore_X_Window window, - Ecore_X_Window_Type *type) +EAPI Eina_Bool +ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, + Ecore_X_Action action) { - Ecore_X_Atom *atoms; - int num; - int i; + int num = 0, i = 0; + Ecore_X_Atom *atoms, atom; + Eina_Bool ret = EINA_FALSE; - if (type) *type = ECORE_X_WINDOW_TYPE_NORMAL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - num = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, - &atoms); - if (num < 0) - { - /* IMO this is not the place to mix netwm and icccm /kwo */ - /* Check if WM_TRANSIENT_FOR is set */ - - /* Disable it for xcb */ - -/* if ((type) && (ecore_x_icccm_transient_for_get(window))) */ -/* *type = ECORE_X_WINDOW_TYPE_DIALOG; */ -/* return 1; */ - } + num = + ecore_x_window_prop_atom_list_get(win, ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); + if (num <= 0) return EINA_FALSE; - if (type) - { - for (i = 0; i < num; ++i) - { - *type = _ecore_x_netwm_window_type_type_get(atoms[i]); - if (*type != ECORE_X_WINDOW_TYPE_UNKNOWN) - break; - } - } - - free(atoms); - - return 1; -} - -static Ecore_X_Atom -_ecore_x_netwm_action_atom_get(Ecore_X_Action action) -{ - switch (action) + atom = _ecore_xcb_netwm_action_atom_get(action); + for (i = 0; i < num; i++) { - 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; - default: - return 0; + if (atoms[i] == atom) + { + ret = EINA_TRUE; + break; + } } -} - -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_allowed_action_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, ECORE_X_ATOM_ATOM, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + if (atoms) free(atoms); + return ret; } -/** - * Gets the reply of the GetProperty request sent by ecore_x_allowed_action_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_allowed_action_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/* FIXME: Get complete list */ - -/** - * Check whether an action is supported by a window. - * @param window The window - * @param action The action - * @return 1 if set, 0 otherwise. - * - * Return whether the user operation @p action is supported by the - * Window Manager for @p window. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_allowed_action_isset(Ecore_X_Window window, - Ecore_X_Action action) +EAPI Eina_Bool +ecore_x_netwm_allowed_action_get(Ecore_X_Window win, + Ecore_X_Action **action, + unsigned int *num) { Ecore_X_Atom *atoms; - Ecore_X_Atom atom; - int num; - int ret = 0; - int i; + int num_ret = 0; - num = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, - &atoms); - if (num <= 0) - return ret; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - atom = _ecore_x_netwm_action_atom_get(action); + if (num) *num = 0; + if (action) *action = NULL; - for (i = 0; i < num; ++i) + 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) { - if (atom == atoms[i]) - { - ret = 1; - break; - } + *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 ret; + return EINA_TRUE; } -/* FIXME: Set complete list */ -/** - * Set the _NET_WM_ALLOWED_ACTIONS property. - * @param window The window. - * @param action An array of allowed actions. - * @param num The number of actions. - * - * Set the user operations that the Window Manager supports for - * @p window by sending the _NET_WM_ALLOWED_ACTIONS property to - * @p window. @p action stores @p num actions. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ EAPI void -ecore_x_netwm_allowed_action_set(Ecore_X_Window window, +ecore_x_netwm_allowed_action_set(Ecore_X_Window win, Ecore_X_Action *action, unsigned int num) { - Ecore_X_Atom *set; - unsigned int i; + Ecore_X_Atom *set; + unsigned int i = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (!num) { - ecore_x_window_prop_property_del(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS); - return; + 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(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, set, num); + 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); } -/** - * Get the allowed actions supported by a window. - * @param window The window. - * @param action The returned array of the actions. - * @param num The number of actions. - * @return 1 on success, 0 otherwise. - * - * Retrieve the user operations that the Window Manager supports for - * @p window and store them in @p action. The number of actions is - * stored in @p num. This function returns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_allowed_action_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_allowed_action_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_allowed_action_get(Ecore_X_Window window, - Ecore_X_Action **action, - unsigned int *num) +/* local functions */ +int +_ecore_xcb_netwm_startup_info_begin(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__) { - Ecore_X_Atom *atoms; - int num_ret; - int i; - - if (num) *num = 0; - if (action) *action = NULL; - - num_ret = ecore_x_window_prop_atom_list_get(window, ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, - &atoms); - if (num_ret <= 0) - return 0; - - 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 1; + // TODO: TBD + return 1; } -/** - * Set the _NET_WM_WINDOW_OPACITY property. - * @param window The window. - * @param opacity The opacity value. - * - * Set the desired opacity of @p window by sending the - * _NET_WM_WINDOW_OPACITY property to @p window. @p opacity is 0 for a - * transparent window and 0xffffffff for an opaque window. @p opacity - * must be multiplied with the original alpha value of @p window - * (which is 1 for visuals not including an alpha component) so that - * @p window content is modulated by the opacity value. - * - * Window Managers acting as compositing managers MAY take this into - * account when displaying a window. Window Managers MUST forward the - * value of this property to any enclosing frame window. This - * property MAY change while the window is mapped and the Window - * Manager MUST respect changes while the window is mapped. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_opacity_set(Ecore_X_Window window, - unsigned int opacity) +int +_ecore_xcb_netwm_startup_info(Ecore_X_Window win __UNUSED__, + uint8_t data __UNUSED__) { - uint32_t op = opacity; - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, - &op, 1); + // TODO: TBD + return 1; } -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_opacity_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; +/* static void */ +/* _ecore_xcb_netwm_startup_info_free(void *data) */ +/* { */ +/* Ecore_Xcb_Startup_Info *info; */ - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); -} +/* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_opacity_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_opacity_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the opacity value of a window. - * @param window The window. - * @param opacity The returned opacity. - * @return 1 on success, 0 otherwise. - * - * Retriee the opacity value of @p window and store it in - * @p opacity. This function returns 1 on sucess, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_opacity_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_opacity_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_opacity_get(Ecore_X_Window window, - unsigned int *opacity) -{ - int ret; - unsigned int tmp; +/* 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); */ +/* } */ - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, - &tmp, 1); - if (opacity) *opacity = tmp; - return ret == 1 ? 1 : 0; -} - -/** - * Set the _NET_FRAME_EXTENTS property. - * @param window The window. - * @param fl The number of pixels of the left border of the window. - * @param fr The number of pixels of the right border of the window. - * @param ft The number of pixels of the top border of the window. - * @param fb The number of pixels of the bottom border of the window. - * - * Set the border witdh of @p window by sending the _NET_FRAME_EXTENTS - * property to @p window. @p fl, @p fr, @p ft and @p fb are respectively - * the number of pixels of the left, right, top and bottom border of - * @p window. - * - * The Window Manager MUST set _NET_FRAME_EXTENTS to the extents of - * the window's frame. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_frame_size_set(Ecore_X_Window window, - int fl, - int fr, - int ft, - int fb) +static Ecore_X_Atom +_ecore_xcb_netwm_window_type_atom_get(Ecore_X_Window_Type type) { - uint32_t frames[4]; - - frames[0] = fl; - frames[1] = fr; - frames[2] = ft; - frames[3] = fb; - ecore_x_window_prop_card32_set(window, ECORE_X_ATOM_NET_FRAME_EXTENTS, frames, 4); -} + switch (type) + { + case ECORE_X_WINDOW_TYPE_DESKTOP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP; -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_frame_size_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; + case ECORE_X_WINDOW_TYPE_DOCK: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DOCK; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_FRAME_EXTENTS, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); -} + case ECORE_X_WINDOW_TYPE_TOOLBAR: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR; -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_frame_size_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_frame_size_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the frame extent of a window. - * @param window The window. - * @param fl The number of pixels of the left border of the window. - * @param fr The number of pixels of the right border of the window. - * @param ft The number of pixels of the top border of the window. - * @param fb The number of pixels of the bottom border of the window. - * @return 1 on success, 0 otherwise. - * - * Retrieve the frame extents of @p window. The number of pixels of - * the left, right, top and bottom border of @p window are - * respectively stored in @p fl, @p fr, @p ft anfd @p fb. TYhis - * function retuirns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_frame_size_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_frame_size_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_frame_size_get(Ecore_X_Window window, - int *fl, - int *fr, - int *ft, - int *fb) -{ - uint32_t frames[4]; - int ret = 0; + case ECORE_X_WINDOW_TYPE_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_MENU; - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_FRAME_EXTENTS, frames, 4); - if (ret != 4) - return 0; + case ECORE_X_WINDOW_TYPE_UTILITY: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY; - if (fl) *fl = frames[0]; - if (fr) *fr = frames[1]; - if (ft) *ft = frames[2]; - if (fb) *fb = frames[3]; - return 1; -} + case ECORE_X_WINDOW_TYPE_SPLASH: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_SPLASH; -/** - * Sends the GetProperty request. - * @param window The window. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_sync_counter_get_prefetch(Ecore_X_Window window) -{ - xcb_get_property_cookie_t cookie; + case ECORE_X_WINDOW_TYPE_DIALOG: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); -} + case ECORE_X_WINDOW_TYPE_NORMAL: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NORMAL; -/** - * Gets the reply of the GetProperty request sent by ecore_x_netwm_sync_counter_get_prefetch(). - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_sync_counter_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/** - * Get the X ID of a X Sync counter. - * @param window The window. - * @param counter The X ID of the Sync counter. - * @return 1 on success, 0 otherwise. - * - * Retrieve the X ID of the X Sync counter of @p window and store it - * in @p counter. This function returns 1 on success, 0 otherwise. - * - * To use this function, you must call before, and in order, - * ecore_x_netwm_frame_size_get_prefetch(), which sends the GetProperty request, - * then ecore_x_netwm_frame_size_get_fetch(), which gets the reply. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_netwm_sync_counter_get(Ecore_X_Window window, - Ecore_X_Sync_Counter *counter) -{ - int ret; - unsigned int tmp; + case ECORE_X_WINDOW_TYPE_DROPDOWN_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DROPDOWN_MENU; - ret = ecore_x_window_prop_card32_get(window, ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, - &tmp, 1); + case ECORE_X_WINDOW_TYPE_POPUP_MENU: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_POPUP_MENU; - if (counter) *counter = tmp; - return (ret == 1) ? 1 : 0; -} + case ECORE_X_WINDOW_TYPE_TOOLTIP: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLTIP; -/** - * Send a _NET_WM_PING property event. - * @param window The window. - * - * Send a ClientMessage event from @p window with the _NET_WM_PING - * property set. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_ping_send(Ecore_X_Window window) -{ - xcb_client_message_event_t ev; + case ECORE_X_WINDOW_TYPE_NOTIFICATION: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION; - if (!window) return; + case ECORE_X_WINDOW_TYPE_COMBO: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_COMBO; - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.sequence = 0; - ev.window = window; - ev.type = ECORE_X_ATOM_WM_PROTOCOLS; - ev.data.data32[0] = ECORE_X_ATOM_NET_WM_PING; - ev.data.data32[1] = XCB_CURRENT_TIME; - ev.data.data32[2] = window; - ev.data.data32[3] = 0; - ev.data.data32[4] = 0; - ev.data.data32[5] = 0; + case ECORE_X_WINDOW_TYPE_DND: + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DND; - xcb_send_event(_ecore_xcb_conn, 0, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); + default: + return 0; + } } -/** - * Send a _NET_WM_SYNC_REQUEST property event. - * @param window The window. - * @param serial The update request number. - * - * Send a ClientMessage event from @p window with the _NET_WM_SYNC_REQUEST - * property set. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_sync_request_send(Ecore_X_Window window, - unsigned int serial) -{ - xcb_client_message_event_t ev; - - if (!window) return; - - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.window = window; - ev.type = ECORE_X_ATOM_WM_PROTOCOLS; - ev.data.data32[0] = ECORE_X_ATOM_NET_WM_SYNC_REQUEST; - ev.data.data32[1] = XCB_CURRENT_TIME; - ev.data.data32[2] = serial; - /* FIXME: imho, the following test is useless as serial is non negative */ - /* should we remove it ? */ - ev.data.data32[3] = (serial < 0) ? ~0L : 0L; - ev.data.data32[4] = 0; - - xcb_send_event(_ecore_xcb_conn, 0, window, 0, (const char *)&ev); -} - -/** - * Send a _NET_WM_STATE property event. - * @param window The window. - * @param root The root window. - * @param s1 The first state to alter. - * @param s2 The second state to alter. - * @param set 0 to unset the property, set it otherwise. - * - * Send a ClientMessage event from @p window to the @p root window - * with the _NET_WM_STATE property set. This change the state of a - * mapped window. @p s1 is the first state to alter. @p s2 is the - * second state to alter. If @p set value is 0, the property is - * removed (or unset), otherwise, the property is set. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_state_request_send(Ecore_X_Window window, - Ecore_X_Window root, - Ecore_X_Window_State s1, - Ecore_X_Window_State s2, - int set) +static Ecore_X_Window_Type +_ecore_xcb_netwm_window_type_type_get(Ecore_X_Atom atom) { - xcb_client_message_event_t ev; - - if (!window) return; - if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.window = window; - ev.type = ECORE_X_ATOM_NET_WM_STATE; - ev.data.data32[0] = !!set; - ev.data.data32[1] = _ecore_x_netwm_state_atom_get(s1); - ev.data.data32[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 */ - ev.data.data32[3] = 1; - ev.data.data32[4] = 0; + 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; +} - xcb_send_event(_ecore_xcb_conn, 0, root, - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&ev); -} - -/** - * Send a _NET_WM_DESKTOP property event. - * @param window The window. - * @param root The root window. - * @param desktop The new desktop index. - * - * Send a ClientMessage event from @p window to the @p root window - * with the _NET_WM_DESKTOP property set. This change the state of a - * non-withdrawn window. @p desktop is the new desktop index to set. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI void -ecore_x_netwm_desktop_request_send(Ecore_X_Window window, - Ecore_X_Window root, - unsigned int desktop) +static Ecore_X_Atom +_ecore_xcb_netwm_window_state_atom_get(Ecore_X_Window_State state) { - xcb_client_message_event_t ev; + switch (state) + { + case ECORE_X_WINDOW_STATE_MODAL: + return ECORE_X_ATOM_NET_WM_STATE_MODAL; - if (!window) return; - if (!root) root = ((xcb_screen_t *)_ecore_xcb_screen)->root; + case ECORE_X_WINDOW_STATE_STICKY: + return ECORE_X_ATOM_NET_WM_STATE_STICKY; - ev.response_type = XCB_CLIENT_MESSAGE | 0x80; - ev.format = 32; - ev.window = window; - ev.type = ECORE_X_ATOM_NET_WM_DESKTOP; - ev.data.data32[0] = desktop; + case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_VERT; - xcb_send_event(_ecore_xcb_conn, 0, root, - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, - (const char *)&ev); -} + case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ: + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ; -int -_ecore_x_netwm_startup_info_begin(Ecore_X_Window window, - char *data) -{ -#if 0 - Ecore_X_Startup_Info *info; + case ECORE_X_WINDOW_STATE_SHADED: + return ECORE_X_ATOM_NET_WM_STATE_SHADED; - if (!startup_info) return 0; - info = ecore_hash_get(startup_info, (void *)window); - if (info) - { - printf("Already got info for win: 0x%x\n", window); - _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; - ecore_hash_set(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); - } -#else - window = XCB_NONE; - data = NULL; -#endif + case ECORE_X_WINDOW_STATE_SKIP_TASKBAR: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_TASKBAR; - return 1; -} + case ECORE_X_WINDOW_STATE_SKIP_PAGER: + return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER; -int -_ecore_x_netwm_startup_info(Ecore_X_Window window, - char *data) -{ -#if 0 - Ecore_X_Startup_Info *info; - char *p; + case ECORE_X_WINDOW_STATE_HIDDEN: + return ECORE_X_ATOM_NET_WM_STATE_HIDDEN; - if (!startup_info) return 0; - info = ecore_hash_get(startup_info, (void *)window); - 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) - { - ecore_hash_remove(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); - } -#else - window = XCB_NONE; - data = NULL; -#endif + case ECORE_X_WINDOW_STATE_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; - return 1; -} + case ECORE_X_WINDOW_STATE_ABOVE: + return ECORE_X_ATOM_NET_WM_STATE_ABOVE; -/* - * Set UTF-8 string property - */ -static void -_ecore_x_window_prop_string_utf8_set(Ecore_X_Window window, - Ecore_X_Atom atom, - const char *str) -{ - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - atom, ECORE_X_ATOM_UTF8_STRING, - 8, strlen(str), str); -} + case ECORE_X_WINDOW_STATE_BELOW: + return ECORE_X_ATOM_NET_WM_STATE_BELOW; -#if 0 -static void -_ecore_x_window_prop_string_utf8_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom) -{ - xcb_get_property_cookie_t cookie; + case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION: + return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, window, - atom, ECORE_X_ATOM_UTF8_STRING, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + default: + return 0; + } } -static void -_ecore_x_window_prop_string_utf8_get_fetch(void) +Ecore_X_Window_State +_ecore_xcb_netwm_window_state_get(Ecore_X_Atom atom) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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; } -#endif -/* - * Get UTF-8 string property - */ -static char * -_ecore_x_window_prop_string_utf8_get(Ecore_X_Window window __UNUSED__, - Ecore_X_Atom atom __UNUSED__) +static Ecore_X_Atom +_ecore_xcb_netwm_action_atom_get(Ecore_X_Action action) { - xcb_get_property_reply_t *reply; - char *str; - int length; + switch (action) + { + case ECORE_X_ACTION_MOVE: + return ECORE_X_ATOM_NET_WM_ACTION_MOVE; - reply = _ecore_xcb_reply_get(); - if (!reply) return NULL; + case ECORE_X_ACTION_RESIZE: + return ECORE_X_ATOM_NET_WM_ACTION_RESIZE; - if ((reply->format != 8) || - (reply->value_len <= 0)) - return NULL; + case ECORE_X_ACTION_MINIMIZE: + return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; - length = reply->value_len; - str = (char *)malloc (sizeof (char) * (length + 1)); - if (!str) - { - return NULL; - } - memcpy(str, xcb_get_property_value(reply), length); - str[length] = '\0'; + case ECORE_X_ACTION_SHADE: + return ECORE_X_ATOM_NET_WM_ACTION_SHADE; - return str; -} + case ECORE_X_ACTION_STICK: + return ECORE_X_ATOM_NET_WM_ACTION_STICK; -#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; + case ECORE_X_ACTION_MAXIMIZE_HORZ: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ; - p = strchr(info->buffer, ':'); - if (!p) - { - ecore_hash_remove(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 - { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; - } + case ECORE_X_ACTION_MAXIMIZE_VERT: + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_VERT; - p++; + case ECORE_X_ACTION_FULLSCREEN: + return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN; - if (!_ecore_x_netwm_startup_info_parse(info, p)) - { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; - } + case ECORE_X_ACTION_CHANGE_DESKTOP: + return ECORE_X_ATOM_NET_WM_ACTION_CHANGE_DESKTOP; - if (info->init) - { - e = calloc(1, sizeof(Ecore_X_Event_Startup_Sequence)); - if (!e) - { - ecore_hash_remove(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); - } + case ECORE_X_ACTION_CLOSE: + return ECORE_X_ATOM_NET_WM_ACTION_CLOSE; - if (event == ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE) - { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - } - else - { - /* Discard buffer */ - info->length = 0; - info->buffer[0] = 0; - } - return 1; -} + case ECORE_X_ACTION_ABOVE: + return ECORE_X_ATOM_NET_WM_ACTION_ABOVE; -/* - * Parse startup info - */ -static int -_ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info, - char *data) -{ + case ECORE_X_ACTION_BELOW: + return ECORE_X_ATOM_NET_WM_ACTION_BELOW; - 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 - { - printf("Ecore X Sequence, Unknown: %s=%s\n", key, value); - } + default: + return 0; } - if (!info->id) return 0; - return 1; } -#endif - -/* - * 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? - */ - -/* FIXME: one round trip can be removed. Can we keep it ? */ - -/** - * Check whether a screen is composited or not. - * @param screen The screen index. - * - * Return 1 if @p screen is composited, 0 otherwise. - * @ingroup Ecore_X_NetWM_Group - */ -EAPI int -ecore_x_screen_is_composited(int screen) -{ - char buf[32]; - xcb_intern_atom_cookie_t cookie_atom; - xcb_get_selection_owner_cookie_t cookie_owner; - xcb_intern_atom_reply_t *reply_atom; - xcb_get_selection_owner_reply_t *reply_owner; - Ecore_X_Window window; - Ecore_X_Atom atom; - - snprintf(buf, sizeof(buf), "_NET_WM_CM_S%d", screen); - cookie_atom = xcb_intern_atom_unchecked(_ecore_xcb_conn, 1, - strlen(buf), buf); - reply_atom = xcb_intern_atom_reply(_ecore_xcb_conn, cookie_atom, NULL); - if (!reply_atom) return 0; - atom = reply_atom->atom; - free(reply_atom); - cookie_owner = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, atom); - reply_owner = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie_owner, NULL); - if (!reply_owner) return 0; - - window = reply_owner->owner; - free(reply_owner); - - return window != XCB_NONE; -} diff --git a/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c index f976f93..f9bf525 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_pixmap.c @@ -1,17 +1,11 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #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 @@ -32,16 +26,19 @@ ecore_x_pixmap_new(Ecore_X_Window win, { 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. * @@ -52,12 +49,15 @@ ecore_x_pixmap_new(Ecore_X_Window win, * @ingroup Ecore_X_Pixmap_Group */ EAPI void -ecore_x_pixmap_del(Ecore_X_Pixmap pmap) +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. @@ -75,18 +75,21 @@ ecore_x_pixmap_del(Ecore_X_Pixmap pmap) EAPI void ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, Ecore_X_Drawable dest, - Ecore_X_GC gc, + Ecore_X_GC gc, int sx, int sy, - int w, + 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. @@ -97,13 +100,18 @@ ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, * @ingroup Ecore_X_Pixmap_Group */ EAPI void -ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, int *x, int *y, int *w, int *h) +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); + ecore_x_drawable_geometry_get(pmap, x, y, w, h); } - /** * Retrieves the depth of the given pixmap. * @param pmap The given pixmap. @@ -113,5 +121,8 @@ 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) { + 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 index 180010c..838c278 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_private.h +++ b/src/lib/ecore_x/xcb/ecore_xcb_private.h @@ -1,319 +1,442 @@ #ifndef __ECORE_XCB_PRIVATE_H__ -#define __ECORE_XCB_PRIVATE_H__ - -#include "config.h" - -#include - -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 256 -#endif - -#ifndef XK_MISCELLANY -# define XK_MISCELLANY 1 -#endif /* XK_MISCELLANY */ - -#include -#include -#include -#include -#ifdef ECORE_XCB_CURSOR -# include -#endif /* ECORE_XCB_CURSOR */ -#ifdef ECORE_XCB_DAMAGE -# include -#endif /* ECORE_XCB_DAMAGE */ -#ifdef ECORE_XCB_COMPOSITE -# include -#endif /* ECORE_XCB_COMPOSITE */ -#ifdef ECORE_XCB_DPMS -# include -#endif /* ECORE_XCB_DPMS */ -#ifdef ECORE_XCB_RANDR -# include -#endif /* ECORE_XCB_RANDR */ -#ifdef ECORE_XCB_RENDER -# include -#endif /* ECORE_XCB_RENDER */ -#ifdef ECORE_XCB_SCREENSAVER -# include -#endif /* ECORE_XCB_SCREENSAVER */ -#ifdef ECORE_XCB_SHAPE -# include -#endif /* ECORE_XCB_SHAPE */ -#ifdef ECORE_XCB_SYNC -# include -#endif /* ECORE_XCB_SYNC */ -#ifdef ECORE_XCB_XFIXES -# include -#endif /* ECORE_XCB_XFIXES */ -#ifdef ECORE_XCB_XINERAMA -# include -#endif /* ECORE_XCB_XINERAMA */ -#ifdef ECORE_XCB_XPRINT -# include -#endif /* ECORE_XCB_XPRINT */ - -#include "ecore_private.h" -#include "Ecore_X.h" - -/* FIXME: this is for simulation only */ -#include "Ecore_Txt.h" - -typedef struct _Ecore_X_Selection_Intern Ecore_X_Selection_Intern; - -struct _Ecore_X_Selection_Intern +# 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 { - Ecore_X_Window win; - Ecore_X_Atom selection; - unsigned char *data; - int length; - Ecore_X_Time time; + 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_Selection_Converter -{ - Ecore_X_Atom target; - int (*convert)(char *target, void *data, int size, - void **data_ret, int *size_ret); - 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 +struct _Ecore_X_DND_Source { - int version; + int version; Ecore_X_Window win, dest; - enum { + 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; + 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; - int suppress; - - int await_status; -} Ecore_X_DND_Source; + int will_accept, suppress; + int await_status; +}; -typedef struct _Ecore_X_DND_Target +struct _Ecore_X_DND_Target { - int version; + int version; Ecore_X_Window win, source; - enum { + enum + { ECORE_X_DND_TARGET_IDLE, ECORE_X_DND_TARGET_ENTERED } state; - struct { + struct + { int x, y; } pos; Ecore_X_Time time; Ecore_X_Atom action, accepted_action; + int will_accept; +}; - int will_accept; -} Ecore_X_DND_Target; - - -extern Ecore_X_Connection *_ecore_xcb_conn; -extern Ecore_X_Screen *_ecore_xcb_screen; -extern double _ecore_xcb_double_click_time; -extern Ecore_X_Time _ecore_xcb_event_last_time; -extern Ecore_X_Window _ecore_xcb_event_last_window; -extern int16_t _ecore_xcb_event_last_root_x; -extern int16_t _ecore_xcb_event_last_root_y; -extern int _ecore_xcb_xcursor; - -extern Ecore_X_Atom _ecore_xcb_atoms_wm_protocols[ECORE_X_WM_PROTOCOL_NUM]; - -extern int _ecore_window_grabs_num; -extern Ecore_X_Window *_ecore_window_grabs; -extern int (*_ecore_window_grab_replay_func) (void *data, int event_type, void *event); -extern void *_ecore_window_grab_replay_data; - -extern Ecore_X_Window _ecore_xcb_private_window; - - -void _ecore_x_error_handler_init(void); - -void _ecore_x_event_handle_key_press (xcb_generic_event_t *event); -void _ecore_x_event_handle_key_release (xcb_generic_event_t *event); -void _ecore_x_event_handle_button_press (xcb_generic_event_t *event); -void _ecore_x_event_handle_button_release (xcb_generic_event_t *event); -void _ecore_x_event_handle_motion_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_enter_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_leave_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_focus_in (xcb_generic_event_t *event); -void _ecore_x_event_handle_focus_out (xcb_generic_event_t *event); -void _ecore_x_event_handle_keymap_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_expose (xcb_generic_event_t *event); -void _ecore_x_event_handle_graphics_expose (xcb_generic_event_t *event); -void _ecore_x_event_handle_visibility_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_create_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_destroy_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_unmap_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_map_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_map_request (xcb_generic_event_t *event); -void _ecore_x_event_handle_reparent_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_configure_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_configure_request (xcb_generic_event_t *event); -void _ecore_x_event_handle_gravity_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_resize_request (xcb_generic_event_t *event); -void _ecore_x_event_handle_circulate_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_circulate_request (xcb_generic_event_t *event); -void _ecore_x_event_handle_property_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_selection_clear (xcb_generic_event_t *event); -void _ecore_x_event_handle_selection_request (xcb_generic_event_t *event); -void _ecore_x_event_handle_selection_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_colormap_notify (xcb_generic_event_t *event); -void _ecore_x_event_handle_client_message (xcb_generic_event_t *event); -void _ecore_x_event_handle_mapping_notify (xcb_generic_event_t *event); -#ifdef ECORE_XCB_DAMAGE -void _ecore_x_event_handle_damage_notify (xcb_generic_event_t *event); -#endif /* ECORE_XCB_DAMAGE */ -#ifdef ECORE_XCB_RANDR -void _ecore_x_event_handle_randr_change (xcb_generic_event_t *event); -#endif /* ECORE_XCB_RANDR */ -#ifdef ECORE_XCB_SCREENSAVER -void _ecore_x_event_handle_screensaver_notify (xcb_generic_event_t *event); -#endif /* ECORE_XCB_SCREENSAVER */ -#ifdef ECORE_XCB_SHAPE -void _ecore_x_event_handle_shape_change (xcb_generic_event_t *event); -#endif /* ECORE_XCB_SHAPE */ -#ifdef ECORE_XCB_SYNC -void _ecore_x_event_handle_sync_counter (xcb_generic_event_t *event); -void _ecore_x_event_handle_sync_alarm (xcb_generic_event_t *event); -#endif /* ECORE_XCB_SYNC */ -#ifdef ECORE_XCB_FIXES -void _ecore_x_event_handle_fixes_selection_notify(xcb_generic_event_t *event); -#endif /* ECORE_XCB_FIXES */ - - -/* requests / replies */ -int _ecore_x_reply_init (); -void _ecore_x_reply_shutdown (); -void _ecore_xcb_cookie_cache (unsigned int cookie); -unsigned int _ecore_xcb_cookie_get (void); -void _ecore_xcb_reply_cache (void *reply); -void *_ecore_xcb_reply_get (void); - - -/* atoms */ -extern Ecore_X_Atom ECORE_X_ATOM_ATOM; -extern Ecore_X_Atom ECORE_X_ATOM_CARDINAL; -extern Ecore_X_Atom ECORE_X_ATOM_STRING; -extern Ecore_X_Atom ECORE_X_ATOM_WINDOW; -extern Ecore_X_Atom ECORE_X_ATOM_E_FRAME_SIZE; -extern Ecore_X_Atom ECORE_X_ATOM_WM_SIZE_HINTS; - -#define ECORE_X_ATOMS_COUNT 115 - -void _ecore_x_atom_init (xcb_intern_atom_cookie_t *); -void _ecore_x_atom_init_finalize (xcb_intern_atom_cookie_t *); - - -/* damage */ -void _ecore_x_damage_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_damage_init_finalize (void); - -/* composite */ -void _ecore_x_composite_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_composite_init_finalize (void); - -/* from dnd */ -void _ecore_x_dnd_init (void); -void _ecore_x_dnd_shutdown (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); - - -/* dpms */ -void _ecore_x_dpms_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_dpms_init_finalize (void); - - -/* 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); - - -/* randr */ -void _ecore_x_randr_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_randr_init_finalize (void); - - -/* selection */ -void _ecore_x_selection_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); -int _ecore_x_selection_set(Ecore_X_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); -void *_ecore_x_selection_parse(const char *target, void *data, int size, int format); - - -/* screensaver */ -void _ecore_x_screensaver_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_screensaver_init_finalize (void); - - -/* shape */ -void _ecore_x_shape_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_shape_init_finalize (void); - - -/* sync */ -void _ecore_x_sync_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_sync_init_finalize (void); - - -/* xfixes */ -void _ecore_x_xfixes_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_xfixes_init_finalize (void); - - -/* xinerama */ -void _ecore_x_xinerama_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_xinerama_init_finalize (void); +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; +}; -/* xprint */ -void _ecore_x_xprint_init (const xcb_query_extension_reply_t *reply); -void _ecore_x_xprint_init_finalize (void); +struct _Ecore_X_Selection_Parser +{ + char *target; + void *(*parse)(const char *target, void *data, int size, int format); + Ecore_X_Selection_Parser *next; +}; -/* to categorize */ -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); +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 /* __ECORE_XCB_PRIVATE_H__*/ +#endif diff --git a/src/lib/ecore_x/xcb/ecore_xcb_randr.c b/src/lib/ecore_x/xcb/ecore_xcb_randr.c index d2e0b9d..a96b047 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_randr.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_randr.c @@ -1,544 +1,3807 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include "ecore_xcb_private.h" - - -/** - * @defgroup Ecore_X_RandR_Group X RandR Extension Functions +/* TODO: List of missing functions * - * Functions related to the X RandR extension. + * 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 int _randr_available = 0; -static xcb_randr_query_version_cookie_t _ecore_xcb_randr_init_cookie; -#endif /* ECORE_XCB_RANDR */ - - -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_randr_init and - _ecore_xcb_randr_init_finalize. The first one gets the cookies and - the second one gets the replies and set the atoms. */ +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_x_randr_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_randr_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_RANDR - if (reply && (reply->present)) - _ecore_xcb_randr_init_cookie = xcb_randr_query_version_unchecked(_ecore_xcb_conn, 1, 2); -#endif /* ECORE_XCB_RANDR */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_randr_id); +#endif } void -_ecore_x_randr_init_finalize(void) +_ecore_xcb_randr_finalize(void) { #ifdef ECORE_XCB_RANDR - xcb_randr_query_version_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_randr_query_version_reply(_ecore_xcb_conn, - _ecore_xcb_randr_init_cookie, NULL); + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (reply) +#ifdef ECORE_XCB_RANDR + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_randr_id); + if ((ext_reply) && (ext_reply->present)) { - if ((reply->major_version >= 1) && - (reply->minor_version >= 1)) - _randr_available = 1; - free(reply); + 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 /* ECORE_XCB_RANDR */ +#endif } -/** - * Return whether the X server supports the RandR Extension. - * @return 1 if the X RandR Extension is available, 0 otherwise. - * - * Return 1 if the X server supports the RandR Extension version 1.1, - * 0 otherwise. - * @ingroup Ecore_X_RandR_Group - */ -EAPI int -ecore_x_randr_query(void) -{ +static Eina_Bool #ifdef ECORE_XCB_RANDR - return _randr_available; +_ecore_xcb_randr_root_validate(Ecore_X_Window root) #else - return 0; -#endif /* ECORE_XCB_RANDR */ -} +_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 Ecore_X_Window -_xcb_randr_root_to_screen(Ecore_X_Window root) +static int +_ecore_xcb_randr_root_to_screen(Ecore_X_Window root) { - xcb_screen_iterator_t iter; + int count = 0, num = 0; - iter = xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)); - for (; iter.rem; xcb_screen_next(&iter)) - { - if (iter.data->root == root) - return iter.data->root; - } + 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 XCB_NONE; + return -1; } -/** - * Select if the ScreenChangeNotify events will be sent. - * @param window The window. - * @param on 1 to enable, 0 to disable. - * @return 1 on success, 0 otherwise. +/* public functions */ + +/* + * @brief Query whether RandR is available or not. * - * If @p on value is @c 1, ScreenChangeNotify events - * will be sent when the screen configuration changes, either from - * this protocol extension, or due to detected external screen - * configuration changes. ScreenChangeNotify may also be sent when - * this request executes if the screen configuration has changed since - * the client connected, to avoid race conditions. - * @ingroup Ecore_X_RandR_Group + * @return @c EINA_TRUE if extension is available, @c EINA_FALSE otherwise. */ -EAPI int -ecore_x_randr_events_select(Ecore_X_Window window, - int on) +EAPI Eina_Bool +ecore_x_randr_query(void) { -#ifdef ECORE_XCB_RANDR - xcb_randr_select_input(_ecore_xcb_conn, window, - on ? XCB_RANDR_SCREEN_CHANGE_NOTIFY : 0); - return 1; -#else - return 0; -#endif /* ECORE_XCB_RANDR */ + return _randr_avail; } -/** - * Sends the GetScreenInfo request. - * @param window Window whose properties are requested. - * @ingroup Ecore_X_RandR_Group +/* + * @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 void -ecore_x_randr_get_screen_info_prefetch(Ecore_X_Window window) +EAPI int +ecore_x_randr_version_get(void) { - xcb_randr_get_screen_info_cookie_t cookie; - - cookie = xcb_randr_get_screen_info_unchecked(_ecore_xcb_conn, - _xcb_randr_root_to_screen(window)); - _ecore_xcb_cookie_cache(cookie.sequence); + return _randr_version; } - -/** - * Gets the reply of the GetScreenInfo request sent by ecore_x_randr_get_screen_info_prefetch(). - * @ingroup Ecore_X_RandR_Group +/* + * @param root window which's primary output will be queried */ -EAPI void -ecore_x_randr_get_screen_info_fetch(void) +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 - cookie.sequence = _ecore_xcb_cookie_get(); - reply =xcb_randr_get_screen_info_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + return ret; } -/** - * Get the set of rotations and reflections. - * @param root The window (Unused). - * @return The set of rotations and reflections. - * - * Get the set of rotations and reflections supported by the screen - * associated to @p window (passed to - * ecore_x_randr_get_screen_info_prefetch()). - * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group +/* + * @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_Rotation -ecore_x_randr_screen_rotations_get(Ecore_X_Window root __UNUSED__) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return reply->rotations; -#else - return 0; -#endif /* ECORE_XCB_RANDR */ +#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; } -/** - * Get the rotation. - * @param root The window (Unused). - * @return The rotation. - * - * Get the rotation supported by the screen - * associated to @p window (passed to - * ecore_x_randr_get_screen_info_prefetch()). +/* + * @brief Sets a given screen's primary output's orientation. * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group + * @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 Ecore_X_Randr_Rotation -ecore_x_randr_screen_rotation_get(Ecore_X_Window root __UNUSED__) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return reply->rotation; -#else - return 0; -#endif /* ECORE_XCB_RANDR */ +#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; } -/** - * Get the frame buffer sizes. - * @param root The window (Unused). - * @param num The number of sizes. - * @return The sizes. - * - * Get the list of possible frame buffer sizes (at the normal - * orientation supported by the screen associated to @p window (passed - * to ecore_x_randr_get_screen_info_prefetch()). Each size indicates - * both the linear physical size of the screen and the pixel size. - * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group +/* + * @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_Screen_Size * -ecore_x_randr_screen_sizes_get(Ecore_X_Window root __UNUSED__, - int *num) +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; - xcb_randr_screen_size_t *sizes; - Ecore_X_Screen_Size *ret; - int n; - int i; + Ecore_X_Randr_Screen_Size_MM *ret = NULL; +#endif - if (num) *num = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply = _ecore_xcb_reply_get(); - if (!reply) - return NULL; +#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; - n = xcb_randr_get_screen_info_sizes_length(reply); - ret = calloc(n, sizeof(Ecore_X_Screen_Size)); - if (!ret) return NULL; + 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; + } - if (num) *num = n; - sizes = xcb_randr_get_screen_info_sizes(reply); - for (i = 0; i < n; i++) - { - ret[i].width = sizes[i].width; - ret[i].height = sizes[i].height; + free(reply); } return ret; #else - if (num) *num = 0; return NULL; -#endif /* ECORE_XCB_RANDR */ +#endif } -/** - * Get the current frame buffer size. - * @param root The window (Unused). - * @return The active size. - * - * Get the active frame buffer size supported by the screen associated - * to @p window (passed to - * ecore_x_randr_get_screen_info_prefetch()). - * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group +/* + * @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 Ecore_X_Screen_Size -ecore_x_randr_current_screen_size_get(Ecore_X_Window root __UNUSED__) +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) { - Ecore_X_Screen_Size ret = { -1, -1 }; #ifdef ECORE_XCB_RANDR + xcb_randr_get_screen_info_cookie_t cookie; xcb_randr_get_screen_info_reply_t *reply; - xcb_randr_screen_size_t *sizes; - uint16_t size_index; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) - return ret; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - size_index = reply->sizeID; - sizes = xcb_randr_get_screen_info_sizes(reply); - if (size_index < reply->nSizes) +#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.width = sizes[size_index].mwidth; - ret.height = sizes[size_index].mheight; - } -#endif /* ECORE_XCB_RANDR */ + int len = 0, idx = 0; + xcb_randr_screen_size_t *sizes; - return ret; + 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 } -/** - * Get the current refresh rate. - * @param root The window (Unused). - * @return The current refresh rate. - * - * Get the current refresh rate supported by the screen associated - * to @p window (passed to - * ecore_x_randr_get_screen_info_prefetch()). +/* + * @brief Sets a given screen's primary output size, but disables all other + * outputs at the same time. * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group + * @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 Ecore_X_Screen_Refresh_Rate -ecore_x_randr_current_screen_refresh_rate_get(Ecore_X_Window root __UNUSED__) +EAPI Eina_Bool +ecore_x_randr_screen_primary_output_size_set(Ecore_X_Window root, + int size_index) { - Ecore_X_Screen_Refresh_Rate ret = { -1 }; + 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 - reply = _ecore_xcb_reply_get(); - if (!reply) - return ret; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - ret.rate = reply->rate; -#endif /* ECORE_XCB_RANDR */ +#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; } -/** - * Get the refresh rates. - * @param root The window (Unused). - * @param num The number of refresh rates. - * @return The refresh rates. - * - * Get the list of refresh rates for each size supported by the screen - * associated to @p window (passed to - * ecore_x_randr_get_screen_info_prefetch()). Each element - * of 'sizes' has a corresponding element in 'refresh'. An empty list - * indicates no known rates, or a device for which refresh is not - * relevant. - * - * To use this function, you must call before, and in order, - * ecore_x_randr_get_screen_info_prefetch(), which sends the GetScreenInfo request, - * then ecore_x_randr_get_screen_info_fetch(), which gets the reply. - * @ingroup Ecore_X_RandR_Group +/* + * @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_Screen_Refresh_Rate * -ecore_x_randr_screen_refresh_rates_get(Ecore_X_Window root __UNUSED__, - int size_id __UNUSED__, - int *num) +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_Screen_Refresh_Rate *ret; - Ecore_X_Screen_Refresh_Rate *tmp; - xcb_randr_refresh_rates_iterator_t iter; - uint16_t n; + Ecore_X_Randr_Refresh_Rate ret = 0.0; +#endif - if (num) *num = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return NULL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - n = reply->nSizes; - ret = calloc(n, sizeof(Ecore_X_Screen_Refresh_Rate)); - if (!ret) - return NULL; - - if (num) *num = n; +#ifdef ECORE_XCB_RANDR + if (!_ecore_xcb_randr_root_validate(root)) return ret; - /* FIXME: maybe there's a missing function in xcb randr implementation */ - iter = xcb_randr_get_screen_info_rates_iterator(reply); - tmp = ret; - for (; iter.rem; xcb_randr_refresh_rates_next(&iter), tmp++) + 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) { - tmp->rate = iter.data->nRates;; + ret = reply->rate; + free(reply); } return ret; #else - if (num) *num = 0; - return NULL; -#endif /* ECORE_XCB_RANDR */ + return 0.0; +#endif } -/* FIXME: round trip. Should we remove it ? */ - -/** - * Set the screen rotation. - * @param root The root window. - * @param rot The rotation. - * - * Set the rotation of the screen associated to @p root. - * - * Note that that function is blocking. - * @ingroup Ecore_X_RandR_Group +/* + * @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 void -ecore_x_randr_screen_rotation_set(Ecore_X_Window root, - Ecore_X_Randr_Rotation rot) +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_set_screen_config_cookie_t cookie; - xcb_randr_set_screen_config_reply_t *reply_config; - xcb_randr_get_screen_info_reply_t *reply; + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; + Ecore_X_Randr_Refresh_Rate *ret = NULL; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, - XCB_CURRENT_TIME, - reply->config_timestamp, - reply->sizeID, - rot, - 0); - reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL); - if (reply_config) - free(reply_config); -#endif /* ECORE_XCB_RANDR */ -} +#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; -/* FIXME: round trip. Should we remove it ? */ + len = xcb_randr_get_screen_info_rates_length(reply); + if (num) *num = len; -/** - * Set the screen size. - * @param root The root window. - * @param size The size. - * - * Set the size of the screen associated to @p root. + 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. * - * Note that that function is blocking. - * @ingroup Ecore_X_RandR_Group + * @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 int -ecore_x_randr_screen_size_set(Ecore_X_Window root, - Ecore_X_Screen_Size size) +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_set_screen_config_cookie_t cookie; - xcb_randr_set_screen_config_reply_t *reply_config; - xcb_randr_get_screen_info_reply_t *reply; - xcb_randr_screen_size_iterator_t iter; - int size_index = -1; - int i; + xcb_randr_get_screen_info_cookie_t cookie; + xcb_randr_get_screen_info_reply_t *reply; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + +#ifdef ECORE_XCB_RANDR + if (_randr_version < RANDR_1_1) return EINA_FALSE; - iter = xcb_randr_get_screen_info_sizes_iterator(reply); - for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++) + 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) { - if ((iter.data->width = size.width) && - (iter.data->height = size.height) && - (iter.data->mwidth = size.width) && - (iter.data->mheight = size.height)) + 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 { - size_index = i; - break; + ret = (sreply->status == XCB_RANDR_SET_CONFIG_SUCCESS) ? + EINA_TRUE : EINA_FALSE; + free(sreply); } + free(reply); } - if (size_index == -1) return 0; +#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; - cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, - XCB_CURRENT_TIME, - reply->config_timestamp, - size_index, - XCB_RANDR_ROTATION_ROTATE_0, - 0); - reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply_config) - return 0; + RANDR_CHECK_1_2_RET(); - free(reply_config); + if (!mode_info) return; - return 1; -#else - return 0; -#endif /* ECORE_XCB_RANDR */ + if (mode_info->name) free(mode_info->name); + free(mode_info); + mode_info = NULL; } -/* FIXME: round trip. Should we remove it ? */ +/* + * @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 -/** - * Set the screen refresh rate. - * @param root The root window. - * @param size The size. - * @param rate The refresh rate. - * - * Set the size and the refresh rate of the screen associated to - * @p root. - * - * Note that that function is blocking. - * @ingroup Ecore_X_RandR_Group + 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 int -ecore_x_randr_screen_refresh_rate_set(Ecore_X_Window root, - Ecore_X_Screen_Size size, - Ecore_X_Screen_Refresh_Rate rate) +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 - xcb_randr_set_screen_config_cookie_t cookie; - xcb_randr_set_screen_config_reply_t *reply_config; - xcb_randr_get_screen_info_reply_t *reply; - xcb_randr_screen_size_iterator_t iter; - int size_index = -1; - int i; + RANDR_CHECK_1_3_RET(); - reply = _ecore_xcb_reply_get(); - if (!reply) - return 0; + 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); - iter = xcb_randr_get_screen_info_sizes_iterator(reply); - for (i = 0; iter.rem; xcb_randr_screen_size_next(&iter), i++) + if (_randr_version >= RANDR_1_3) { - if ((iter.data->width = size.width) && - (iter.data->height = size.height) && - (iter.data->mwidth = size.width) && - (iter.data->mheight = size.height)) - { - size_index = i; - break; - } + 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); } - if (size_index == -1) return 0; +#endif - cookie = xcb_randr_set_screen_config_unchecked(_ecore_xcb_conn, root, - XCB_CURRENT_TIME, - reply->config_timestamp, - size_index, - XCB_RANDR_ROTATION_ROTATE_0, - rate.rate); - reply_config = xcb_randr_set_screen_config_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply_config) - return 0; + return modes; +} - free(reply_config); +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; - return 1; -#else - return 0; -#endif /* ECORE_XCB_RANDR */ +#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 index 6fdf8c4..9b74c67 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_screensaver.c @@ -1,372 +1,370 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" +# ifdef ECORE_XCB_SCREENSAVER +# include +# endif +/* local variables */ +static Eina_Bool _screensaver_avail = EINA_FALSE; -/** - * @defgroup Ecore_X_ScrenSaver_Group X Shape extension - * - * These functions use the shape extension of the X server to change - * shape of given windows. - */ - +/* external variables */ +int _ecore_xcb_event_screensaver = -1; -/** - * Return whether the X server supports the ScrenSaver Extension. - * @return 1 if the X ScrenSaver Extension is available, 0 otherwise. - * - * Return 1 if the X server supports the ScrenSaver Extension version 1.0, - * 0 otherwise. - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI int -ecore_x_screensaver_event_available_get(void) +void +_ecore_xcb_screensaver_init(void) { - return 1; -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); - -/** - * Sends the QueryInfo request. - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI void -ecore_x_screensaver_idle_time_prefetch(void) -{ #ifdef ECORE_XCB_SCREENSAVER - xcb_screensaver_query_info_cookie_t cookie; - - cookie = xcb_screensaver_query_info_unchecked(_ecore_xcb_conn, ((xcb_screen_t *)_ecore_xcb_screen)->root); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_SCREENSAVER */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_screensaver_id); +#endif } - -/** - * Gets the reply of the QueryInfo request sent by ecore_x_get_screensaver_prefetch(). - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI void -ecore_x_screensaver_idle_time_fetch(void) +void +_ecore_xcb_screensaver_finalize(void) { #ifdef ECORE_XCB_SCREENSAVER - xcb_screensaver_query_info_cookie_t cookie; - xcb_screensaver_query_info_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_screensaver_query_info_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_SCREENSAVER */ -} + 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 +} -/** - * Get the number of seconds since the last input was received. - * @return The number of seconds. - * - * Get the number of milliseconds since the last input was received - * from the user on any of the input devices. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI int ecore_x_screensaver_idle_time_get(void) { - int idle = 0; + 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 - reply = _ecore_xcb_reply_get(); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (!reply) return 0; + if (!_screensaver_avail) return 0; - /* FIXME: check if it is ms_since_user_input or ms_until_server */ - idle = reply->ms_since_user_input / 1000; -#endif /* ECORE_XCB_SCREENSAVER */ +#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 idle; + return ret; } - -/** - * Set the parameters of the screen saver. - * @param timeout The timeout, in second. - * @param interval The interval, in seconds. - * @param blank 0 to disable screen blanking, otherwise enable it. - * @param expose Allow Expose generation event or not. - * - * Set the parameters of the screen saver. @p timeout is the timeout, - * in seconds, until the screen saver turns on. @p interval is the - * interval, in seconds, between screen saver alterations. @p blank - * specifies how to enable screen blanking. @p expose specifies the - * screen save control values. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void ecore_x_screensaver_set(int timeout, int interval, - int blank, - int expose) + 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, - (int16_t)timeout, - (int16_t)interval, - (uint8_t)blank, - (uint8_t)expose); + timeout, interval, prefer_blanking, allow_exposures); +#endif } - -/** - * Sends the GetScreenSaver request. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void -ecore_x_get_screensaver_prefetch(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); - _ecore_xcb_cookie_cache(cookie.sequence); + 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 } - -/** - * Gets the reply of the GetScreenSaver request sent by ecore_x_get_screensaver_prefetch(). - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI void -ecore_x_get_screensaver_fetch(void) +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; - cookie.sequence = _ecore_xcb_cookie_get(); +#ifdef ECORE_XCB_SCREENSAVER + cookie = xcb_get_screen_saver_unchecked(_ecore_xcb_conn); reply = xcb_get_screen_saver_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} + if (!reply) return 0; + timeout = reply->timeout; + free(reply); +#endif + return timeout; +} -/** - * Set the timeout of the screen saver. - * @param timeout The timeout to set. - * - * Set the @p timeout, in seconds, until the screen saver turns on. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void -ecore_x_screensaver_timeout_set(int timeout) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - xcb_set_screen_saver(_ecore_xcb_conn, - (int16_t)timeout, - reply->interval, - reply->prefer_blanking, - reply->allow_exposures); -} + 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 +} -/** - * Get the timeout of the screen saver. - * @return The timeout. - * - * Get the @p timeout, in seconds, until the screen saver turns on. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI int -ecore_x_screensaver_timeout_get(void) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return 0.0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return (int)reply->timeout; -} + 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; +} -/** - * Set the interval of the screen saver. - * @param interval The interval to set. - * - * Set the @p interval, in seconds, between screen saver alterations. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void -ecore_x_screensaver_interval_set(int interval) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - xcb_set_screen_saver(_ecore_xcb_conn, - reply->timeout, - (int16_t)interval, - reply->prefer_blanking, - reply->allow_exposures); -} + 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 +} -/** - * Get the interval of the screen saver. - * @return The interval. - * - * Get the @p interval, in seconds, between screen saver alterations. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI int -ecore_x_screensaver_interval_get(void) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return 0.0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return (int)reply->interval; -} + 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; +} -/** - * Set the screen blanking. - * @param blank The blank to set. - * - * @p blank specifies how to enable screen blanking. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void -ecore_x_screensaver_blank_set(int blank) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - xcb_set_screen_saver(_ecore_xcb_conn, - reply->timeout, - reply->interval, - (uint8_t)blank, - reply->allow_exposures); -} + 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 +} -/** - * Get the screen blanking. - * @return The blanking. - * - * Get the screen blanking. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI int -ecore_x_screensaver_blank_get(void) +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 - reply = _ecore_xcb_reply_get(); - if (!reply) return 0.0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return (int)reply->prefer_blanking; -} + 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; +} -/** - * Set the screen save control values. - * @param expose The expose to set. - * - * Set the screen save control values. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ EAPI void -ecore_x_screensaver_expose_set(int expose) +ecore_x_screensaver_event_listen_set(Eina_Bool on) { - xcb_get_screen_saver_reply_t *reply; +#ifdef ECORE_XCB_SCREENSAVER + Ecore_X_Window root; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - xcb_set_screen_saver(_ecore_xcb_conn, - reply->timeout, - reply->interval, - reply->prefer_blanking, - (uint8_t)expose); -} + 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 +} -/** - * Get the screen save control values. - * @return The expose. - * - * Get the screen save control values. - * - * To use this function, you must call before, and in order, - * ecore_x_get_screensaver_prefetch(), which sends the GetScreenSaver request, - * then ecore_x_get_screensaver_fetch(), which gets the reply. - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI int -ecore_x_screensaver_expose_get(void) +EAPI Eina_Bool +ecore_x_screensaver_event_available_get(void) { - xcb_get_screen_saver_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) return 0.0; - - return (int)reply->allow_exposures; + 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 +} -/** - * Specifies if the Screen Saver NotifyMask event should be generated. - * @param on 0 to disable the generation of the event, otherwise enable it. - * - * Specifies if the Screen Saver NotifyMask event on the screen - * associated with drawable should be generated for this client. If - * @p on is set to @c 0, the generation is disabled, otherwise, it is - * enabled. - * @ingroup Ecore_X_ScrenSaver_Group - */ -EAPI void -ecore_x_screensaver_event_listen_set(int on) +EAPI Eina_Bool +ecore_x_screensaver_custom_blanking_disable(void) { #ifdef ECORE_XCB_SCREENSAVER - xcb_screensaver_select_input(_ecore_xcb_conn, - ((xcb_screen_t *)_ecore_xcb_screen)->root, - on ? XCB_SCREENSAVER_EVENT_NOTIFY_MASK : 0); -#endif /* 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 index dd4d075..2fe148b 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_selection.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_selection.c @@ -1,1062 +1,1026 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.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; +//#include "Ecore_X_Atoms.h" -static int _ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret); -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)) +#define ECORE_XCB_SELECTION_DATA(x) ((Ecore_X_Selection_Data *)(x)) +/* local function prototypes */ +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_x_selection_init(void) +_ecore_xcb_selection_init(void) { - /* Initialize global data */ - memset(selections, 0, sizeof(selections)); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + memset(_selections, 0, sizeof(_selections)); - /* Initialize converters */ + /* init 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_text); ecore_x_selection_converter_atom_add(ECORE_X_ATOM_UTF8_STRING, - _ecore_x_selection_converter_text); -#endif + ecore_x_selection_converter_text); ecore_x_selection_converter_atom_add(ECORE_X_ATOM_COMPOUND_TEXT, - _ecore_x_selection_converter_text); + ecore_x_selection_converter_text); ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING, - _ecore_x_selection_converter_text); + ecore_x_selection_converter_text); - /* Initialize parsers */ + /* init parsers */ ecore_x_selection_parser_add("text/plain", - _ecore_x_selection_parser_text); + _ecore_xcb_selection_parser_text); ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_UTF8_STRING, - _ecore_x_selection_parser_text); + _ecore_xcb_selection_parser_text); ecore_x_selection_parser_add("text/uri-list", - _ecore_x_selection_parser_files); + _ecore_xcb_selection_parser_files); ecore_x_selection_parser_add("_NETSCAPE_URL", - _ecore_x_selection_parser_files); + _ecore_xcb_selection_parser_files); ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS, - _ecore_x_selection_parser_targets); + _ecore_xcb_selection_parser_targets); } void -_ecore_x_selection_shutdown(void) +_ecore_xcb_selection_shutdown(void) { Ecore_X_Selection_Converter *cnv; Ecore_X_Selection_Parser *prs; - /* free the selection converters */ - cnv = converters; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + /* free selection converters */ + cnv = _converters; while (cnv) { - Ecore_X_Selection_Converter *tmp; + Ecore_X_Selection_Converter *tmp; - tmp = cnv->next; - free(cnv); - cnv = tmp; + tmp = cnv->next; + free(cnv); + cnv = tmp; } - converters = NULL; + _converters = NULL; - /* free the selection parsers */ - prs = parsers; + /* free parsers */ + prs = _parsers; while (prs) { - Ecore_X_Selection_Parser *tmp; + Ecore_X_Selection_Parser *tmp; - tmp = prs; - prs = prs->next; - free(tmp->target); - free(tmp); + tmp = prs; + prs = prs->next; + free(tmp->target); + free(tmp); } - parsers = NULL; + _parsers = NULL; } -Ecore_X_Selection_Intern * -_ecore_x_selection_get(Ecore_X_Atom selection) +/* 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)) { - 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]; + 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 - return NULL; + { + _converters = calloc(1, sizeof(Ecore_X_Selection_Converter)); + if (!_converters) return; + cnv = _converters; + } + cnv->target = target; + cnv->convert = func; } - -/* - * Sends the GetSelectionOwner request. - */ -void -_ecore_xcb_get_selection_owner_prefetch(Ecore_X_Atom selection) +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)) { - xcb_get_selection_owner_cookie_t cookie; + Ecore_X_Atom atarget; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, selection); - _ecore_xcb_cookie_cache(cookie.sequence); + if ((!func) || (!target)) return; + atarget = _ecore_xcb_selection_target_atom_get(target); + ecore_x_selection_converter_atom_add(atarget, func); } -/* - * Gets the reply of the GetSelectionOwner request sent by _ecore_xcb_get_selection_owner_prefetch(). - */ -void -_ecore_xcb_get_selection_owner_fetch(void) +EAPI void +ecore_x_selection_converter_del(char *target) { - xcb_get_selection_owner_cookie_t cookie; - xcb_get_selection_owner_reply_t *reply; + Ecore_X_Atom atarget; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!target) return; + atarget = _ecore_xcb_selection_target_atom_get(target); + ecore_x_selection_converter_atom_del(atarget); } -/* - * To use this function, you must call before, and in order, - * _ecore_xcb_get_selection_owner_prefetch(), which sends the GetSelectionOwner request, - * then _ecore_xcb_get_selection_owner_fetch(), which gets the reply. - */ -int -_ecore_x_selection_set(Ecore_X_Window window, - const void *data, - int size, - Ecore_X_Atom selection) +EAPI void +ecore_x_selection_converter_atom_del(Ecore_X_Atom target) { - xcb_get_selection_owner_reply_t *reply; - unsigned char *buf = NULL; - int in; + Ecore_X_Selection_Converter *conv, *pconv = NULL; - xcb_set_selection_owner(_ecore_xcb_conn, window, selection, _ecore_xcb_event_last_time); + LOGFN(__FILE__, __LINE__, __FUNCTION__); - reply = _ecore_xcb_reply_get(); - if (!reply || (reply->owner != window)) return 0; + 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; + } +} - 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 0; +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 (data) + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!target) return; + prs = _parsers; + if (prs) { - selections[in].win = window; - selections[in].selection = selection; - selections[in].length = size; - selections[in].time = _ecore_xcb_event_last_time; - - buf = malloc(size); - memcpy(buf, data, size); - selections[in].data = buf; + 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 { - if (selections[in].data) - { - free(selections[in].data); - memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data)); - } + _parsers = calloc(1, sizeof(Ecore_X_Selection_Parser)); + prs = _parsers; } - - return 1; + prs->target = strdup(target); + prs->parse = func; } - -/** - * Sends the GetSelectionOwner request. - */ EAPI void -ecore_x_selection_primary_prefetch(void) +ecore_x_selection_parser_del(const char *target) { - xcb_get_selection_owner_cookie_t cookie; + Ecore_X_Selection_Parser *prs, *pprs = NULL; - cookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, ECORE_X_ATOM_SELECTION_PRIMARY); - _ecore_xcb_cookie_cache(cookie.sequence); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); -/** - * Gets the reply of the GetSelectionOwner request sent by ecore_x_selection_primary_prefetch(). - */ -EAPI void -ecore_x_selection_primary_fetch(void) -{ - xcb_get_selection_owner_cookie_t cookie; - xcb_get_selection_owner_reply_t *reply; + if (!target) return; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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 window 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_primary_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_primary_fetch(), which gets the reply. + * @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 int -ecore_x_selection_primary_set(Ecore_X_Window window, +EAPI Eina_Bool +ecore_x_selection_primary_set(Ecore_X_Window win, const void *data, int size) { - return _ecore_x_selection_set(window, data, size, ECORE_X_ATOM_SELECTION_PRIMARY); + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_primary_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_primary_fetch(), which gets the reply. */ -EAPI int +EAPI Eina_Bool ecore_x_selection_primary_clear(void) { - return _ecore_x_selection_set(XCB_NONE, NULL, 0, ECORE_X_ATOM_SELECTION_PRIMARY); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); - -/** - * Sends the GetSelectionOwner request. - */ -EAPI void -ecore_x_selection_secondary_prefetch(void) -{ - xcb_get_selection_owner_cookie_t cookie; - - cookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, ECORE_X_ATOM_SELECTION_SECONDARY); - _ecore_xcb_cookie_cache(cookie.sequence); + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_PRIMARY); } -/** - * Gets the reply of the GetSelectionOwner request sent by ecore_x_selection_secondary_prefetch(). - */ EAPI void -ecore_x_selection_secondary_fetch(void) +ecore_x_selection_primary_request(Ecore_X_Window win, + const char *target) { - xcb_get_selection_owner_cookie_t cookie; - xcb_get_selection_owner_reply_t *reply; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_PRIMARY, target); } - /** * Claim ownership of the SECONDARY selection and set its data. - * @param window 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_secondary_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_secondary_fetch(), which gets the reply. + * @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 int -ecore_x_selection_secondary_set(Ecore_X_Window window, +EAPI Eina_Bool +ecore_x_selection_secondary_set(Ecore_X_Window win, const void *data, int size) { - return _ecore_x_selection_set(window, data, size, ECORE_X_ATOM_SELECTION_SECONDARY); + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_secondary_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_secondary_fetch(), which gets the reply. */ -EAPI int +EAPI Eina_Bool ecore_x_selection_secondary_clear(void) { - return _ecore_x_selection_set(XCB_NONE, NULL, 0, ECORE_X_ATOM_SELECTION_SECONDARY); -} - - -/** - * Sends the GetSelectionOwner request. - */ -EAPI void -ecore_x_selection_xdnd_prefetch(void) -{ - xcb_get_selection_owner_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, ECORE_X_ATOM_SELECTION_XDND); - _ecore_xcb_cookie_cache(cookie.sequence); + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_SECONDARY); } -/** - * Gets the reply of the GetSelectionOwner request sent by ecore_x_selection_xdnd_prefetch(). - */ EAPI void -ecore_x_selection_xdnd_fetch(void) +ecore_x_selection_secondary_request(Ecore_X_Window win, + const char *target) { - xcb_get_selection_owner_cookie_t cookie; - xcb_get_selection_owner_reply_t *reply; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_SECONDARY, target); } /** * Claim ownership of the XDND selection and set its data. - * @param window 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_xdnd_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_xdnd_fetch(), which gets the reply. + * @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 int -ecore_x_selection_xdnd_set(Ecore_X_Window window, +EAPI Eina_Bool +ecore_x_selection_xdnd_set(Ecore_X_Window win, const void *data, int size) { - return _ecore_x_selection_set(window, data, size, ECORE_X_ATOM_SELECTION_XDND); + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_xdnd_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_xdnd_fetch(), which gets the reply. */ -EAPI int +EAPI Eina_Bool ecore_x_selection_xdnd_clear(void) { - return _ecore_x_selection_set(XCB_NONE, NULL, 0, ECORE_X_ATOM_SELECTION_XDND); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_XDND); +} -/** - * Sends the GetSelectionOwner request. - */ EAPI void -ecore_x_selection_clipboard_prefetch(void) +ecore_x_selection_xdnd_request(Ecore_X_Window win, + const char *target) { - xcb_get_selection_owner_cookie_t cookie; + Ecore_X_Atom atom; + Ecore_X_DND_Target *_target; - cookie = xcb_get_selection_owner_unchecked(_ecore_xcb_conn, ECORE_X_ATOM_SELECTION_CLIPBOARD); - _ecore_xcb_cookie_cache(cookie.sequence); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * Gets the reply of the GetSelectionOwner request sent by ecore_x_selection_clipboard_prefetch(). - */ -EAPI void -ecore_x_selection_clipboard_fetch(void) -{ - xcb_get_selection_owner_cookie_t cookie; - xcb_get_selection_owner_reply_t *reply; + _target = _ecore_xcb_dnd_target_get(); + atom = _ecore_xcb_selection_target_atom_get(target); - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_selection_owner_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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 window 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. + * @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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_clipboard_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_clipboard_fetch(), which gets the reply. */ -EAPI int -ecore_x_selection_clipboard_set(Ecore_X_Window window, +EAPI Eina_Bool +ecore_x_selection_clipboard_set(Ecore_X_Window win, const void *data, int size) { - return _ecore_x_selection_set(window, data, size, ECORE_X_ATOM_SELECTION_CLIPBOARD); + 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. - * - * To use this function, you must call before, and in order, - * ecore_x_selection_clipboard_prefetch(), which sends the GetSelectionOwner request, - * then ecore_x_selection_clipboard_fetch(), which gets the reply. */ -EAPI int +EAPI Eina_Bool ecore_x_selection_clipboard_clear(void) { - return _ecore_x_selection_set(XCB_NONE, NULL, 0, ECORE_X_ATOM_SELECTION_CLIPBOARD); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_xcb_selection_set(XCB_NONE, NULL, 0, + ECORE_X_ATOM_SELECTION_CLIPBOARD); +} -/* FIXME: roundtrip if target is not handled in the tests */ -Ecore_X_Atom -_ecore_x_selection_target_atom_get(const char *target) +EAPI void +ecore_x_selection_clipboard_request(Ecore_X_Window win, + const char *target) { - Ecore_X_Atom x_target = XCB_NONE; - - 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 - { - xcb_intern_atom_cookie_t cookie; - xcb_intern_atom_reply_t *reply; - - cookie = xcb_intern_atom_unchecked(_ecore_xcb_conn, 0, - strlen(target), target); - reply = xcb_intern_atom_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - return XCB_NONE; - x_target = reply->atom; - free(reply); - } + LOGFN(__FILE__, __LINE__, __FUNCTION__); - return x_target; + _ecore_xcb_selection_request(win, ECORE_X_ATOM_SELECTION_CLIPBOARD, target); } - -/* FIXME: roundtrip if target is not handled in the tests */ -char * -_ecore_x_selection_target_get(Ecore_X_Atom 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) { - 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 - { - xcb_get_atom_name_cookie_t cookie; - xcb_get_atom_name_reply_t *reply; - char *name; + Ecore_X_Selection_Intern *sel; + Ecore_X_Selection_Converter *cnv; + void *data; + char *tgt_str; - cookie = xcb_get_atom_name_unchecked(_ecore_xcb_conn, target); - reply = xcb_get_atom_name_reply(_ecore_xcb_conn, cookie, NULL); - if (!reply) - return NULL; - name = (char *)malloc(sizeof(char) * (reply->length + 1)); - if (!name) + 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) { - free(reply); - return NULL; + 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; } - memcpy(name, xcb_get_atom_name_name(reply), reply->length); - name[reply->length] = '\0'; - free(reply); - return name; } + + return EINA_FALSE; } -static void -_ecore_x_selection_request(Ecore_X_Window window, - Ecore_X_Atom selection, - const char *target_str) +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) { - Ecore_X_Atom target, prop; + xcb_selection_notify_event_t ev; - target = _ecore_x_selection_target_atom_get(target_str); + 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; + memset(&ev, 0, sizeof(xcb_selection_notify_event_t)); - xcb_convert_selection(_ecore_xcb_conn, window, - selection, target, prop, - XCB_CURRENT_TIME); -} + ev.response_type = XCB_SELECTION_NOTIFY; + ev.requestor = requestor; + ev.selection = selection; + ev.target = target; + ev.property = property; + ev.time = tim; -EAPI void -ecore_x_selection_primary_request(Ecore_X_Window window, - const char *target) -{ - _ecore_x_selection_request(window, ECORE_X_ATOM_SELECTION_PRIMARY, target); -} + xcb_send_event(_ecore_xcb_conn, 0, requestor, + XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); +// ecore_x_flush(); -EAPI void -ecore_x_selection_secondary_request(Ecore_X_Window window, - const char *target) -{ - _ecore_x_selection_request(window, ECORE_X_ATOM_SELECTION_SECONDARY, target); + return EINA_TRUE; } EAPI void -ecore_x_selection_xdnd_request(Ecore_X_Window window, - const char *target) +ecore_x_selection_owner_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Time tim) { - Ecore_X_Atom atom; - Ecore_X_DND_Target *_target; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - _target = _ecore_x_dnd_target_get(); - atom = _ecore_x_selection_target_atom_get(target); - xcb_convert_selection(_ecore_xcb_conn, window, - ECORE_X_ATOM_SELECTION_XDND, atom, - ECORE_X_ATOM_SELECTION_PROP_XDND, - _target->time); + xcb_set_selection_owner(_ecore_xcb_conn, win, atom, tim); } -EAPI void -ecore_x_selection_clipboard_request(Ecore_X_Window window, const char *target) +EAPI Ecore_X_Window +ecore_x_selection_owner_get(Ecore_X_Atom atom) { - _ecore_x_selection_request(window, ECORE_X_ATOM_SELECTION_CLIPBOARD, target); -} + xcb_get_selection_owner_cookie_t cookie; + xcb_get_selection_owner_reply_t *reply; + Ecore_X_Window ret; -EAPI void -ecore_x_selection_converter_atom_add(Ecore_X_Atom target, - int (*func)(char *target, - void *data, - int size, - void **data_ret, - int *size_ret)) -{ - Ecore_X_Selection_Converter *cnv; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - 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)); - cnv = cnv->next; - } - else - { - converters = calloc(1, sizeof(Ecore_X_Selection_Converter)); - cnv = converters; - } - cnv->target = target; - cnv->convert = func; + 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; } -EAPI void -ecore_x_selection_converter_add(char *target, - int (*func)(char *target, - void *data, - int size, - void **data_ret, - int *size_ret)) +void * +_ecore_xcb_selection_parse(const char *target, + void *data, + int size, + int format) { - Ecore_X_Atom x_target; + Ecore_X_Selection_Parser *prs; + Ecore_X_Selection_Data *sel; - if (!func || !target) - return; + for (prs = _parsers; prs; prs = prs->next) + { + if (!strcmp(prs->target, target)) + { + sel = prs->parse(target, data, size, format); + if (sel) return sel; + } + } - x_target = _ecore_x_selection_target_atom_get(target); + 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; - ecore_x_selection_converter_atom_add(x_target, func); + return sel; } -EAPI void -ecore_x_selection_converter_atom_del(Ecore_X_Atom target) +Ecore_X_Selection_Intern * +_ecore_xcb_selection_get(Ecore_X_Atom selection) { - Ecore_X_Selection_Converter *cnv, *prev_cnv; - - 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; - } + 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; } -EAPI void -ecore_x_selection_converter_del(char *target) +/* local functions */ +static Eina_Bool +_ecore_xcb_selection_set(Ecore_X_Window win, + const void *data, + int size, + Ecore_X_Atom selection) { - Ecore_X_Atom x_target; + xcb_get_selection_owner_cookie_t cookie; + xcb_get_selection_owner_reply_t *reply; + int in = 0; - if (!target) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - x_target = _ecore_x_selection_target_atom_get(target); - ecore_x_selection_converter_atom_del(x_target); -} + xcb_set_selection_owner(_ecore_xcb_conn, win, selection, XCB_CURRENT_TIME); -EAPI int -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) -{ - xcb_selection_notify_event_t ev; + 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; - ev.time = time; - ev.requestor = requestor; - ev.selection = selection; - ev.target = target; - ev.property = property; - /* send_event is bit 7 (0x80) of response_type */ - ev.response_type = 0x80; + if (reply->owner != win) + { + free(reply); + return EINA_FALSE; + } + free(reply); - xcb_send_event(_ecore_xcb_conn, 0, - requestor, 0, (const char *)&ev); - return 1; -} + 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; -/* Locate and run conversion callback for specified selection target */ -EAPI int -ecore_x_selection_convert(Ecore_X_Atom selection, - Ecore_X_Atom target, - void **data_ret) -{ - Ecore_X_Selection_Intern *sel; - Ecore_X_Selection_Converter *cnv; - void *data; - char *tgt_str; - int size; + if (data) + { + unsigned char *buff = NULL; - sel = _ecore_x_selection_get(selection); - tgt_str = _ecore_x_selection_target_get(target); + _selections[in].win = win; + _selections[in].selection = selection; + _selections[in].length = size; + _selections[in].time = _ecore_xcb_events_last_time_get(); - for (cnv = converters; cnv; cnv = cnv->next) + buff = malloc(size); + if (!buff) return EINA_FALSE; + memcpy(buff, data, size); + _selections[in].data = buff; + } + else if (_selections[in].data) { - if (cnv->target == target) - { - int r; - r = cnv->convert(tgt_str, sel->data, sel->length, &data, &size); - free(tgt_str); - if (r) - { - *data_ret = data; - return r; - } - else - return 0; - } + free(_selections[in].data); + memset(&_selections[in], 0, sizeof(Ecore_X_Selection_Data)); } - /* Default, just return the data */ - *data_ret = malloc(sel->length); - memcpy(*data_ret, sel->data, sel->length); - free(tgt_str); - return 1; + return EINA_TRUE; } -/* 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 int -_ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret) +static void +_ecore_xcb_selection_request(Ecore_X_Window win, + Ecore_X_Atom selection, + const char *target) { + Ecore_X_Atom atarget, prop; - /* FIXME: to do... */ - -/* XTextProperty text_prop; */ -/* char *mystr; */ -/* XICCEncodingStyle style; */ - -/* if (!data || !size) */ -/* return 0; */ - -/* 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 */ -/* else */ -/* return 0; */ - -/* if (!(mystr = strdup(data))) */ -/* return 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); */ -/* memcpy(*data_ret, text_prop.value, bufsize); */ -/* *size_ret = bufsize; */ -/* XFree(text_prop.value); */ -/* free(mystr); */ -/* return 1; */ -/* } */ -/* #else */ -/* if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, &text_prop) == Success) */ -/* { */ -/* int bufsize = strlen(text_prop.value) + 1; */ -/* *data_ret = malloc(bufsize); */ -/* memcpy(*data_ret, text_prop.value, bufsize); */ -/* *size_ret = bufsize; */ -/* XFree(text_prop.value); */ -/* free(mystr); */ -/* return 1; */ -/* } */ -/* #endif */ -/* else */ -/* { */ -/* free(mystr); */ -/* return 0; */ -/* } */ - - return 0; + 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); } -EAPI void -ecore_x_selection_parser_add(const char *target, - void *(*func)(const char *target, - void *data, - int size, - int format)) +EAPI Eina_Bool +ecore_x_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_X_Selection_Parser *prs; + Ecore_Xcb_Encoding_Style style; + Ecore_Xcb_Textproperty ret; + char *str; - if (!target) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if ((!data) || (!size)) return EINA_FALSE; - prs = parsers; - if (parsers) + 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)) { - 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; + 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 +#else + if (_ecore_xcb_mb_textlist_to_textproperty(&str, 1, style, &ret)) { - parsers = calloc(1, sizeof(Ecore_X_Selection_Parser)); - prs = parsers; + 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; } - prs->target = strdup(target); - prs->parse = func; +#endif + else + return EINA_TRUE; } -EAPI void -ecore_x_selection_parser_del(const char *target) +static void * +_ecore_xcb_selection_parser_text(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__) { - Ecore_X_Selection_Parser *prs, *prev_prs; - - if (!target) - return; + Ecore_X_Selection_Data_Text *sel; + unsigned char *_data; + void *t; - prev_prs = NULL; - prs = parsers; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - 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; - } -} + if (!(_data = data)) return NULL; -/* 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; + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text)); + if (!sel) return NULL; - for (prs = parsers; prs; prs = prs->next) + if (_data[size - 1]) { - if (!strcmp(prs->target, target)) - { - sel = prs->parse(target, data, size, format); - return sel; - } + size++; + t = realloc(_data, size); + if (!t) + { + free(sel); + return NULL; + } + _data = t; + _data[size - 1] = 0; } - - /* Default, just return the data */ - sel = calloc(1, sizeof(Ecore_X_Selection_Data)); - sel->free = _ecore_x_selection_data_default_free; - sel->length = size; - sel->format = format; - sel->data = data; + 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 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_xcb_selection_parser_files(const char *target, + void *data, + int size, + int format __UNUSED__) { Ecore_X_Selection_Data_Files *sel; - char *data = _data; - int i, is; - char *tmp; + char *_data, *tmp, *t, **t2; + int i = 0, is = 0; - if (strcmp(target, "text/uri-list") && - strcmp(target, "_NETSCAPE_URL")) - return NULL; + 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)); - ECORE_X_SELECTION_DATA(sel)->free = _ecore_x_selection_data_files_free; + if (!sel) return NULL; - if (data[size - 1]) + ECORE_XCB_SELECTION_DATA(sel)->free = _ecore_xcb_selection_data_files_free; + + if (_data[size - 1]) { - /* Isn't nul terminated */ - size++; - data = realloc(data, size); - data[size - 1] = 0; + size++; + t = realloc(_data, size); + if (!t) + { + free(sel); + return NULL; + } + _data = t; + _data[size - 1] = 0; } tmp = malloc(size); - i = 0; - is = 0; - while ((is < size) && (data[is])) + 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++; - sel->files = realloc(sel->files, sel->num_files * sizeof(char *)); - sel->files[sel->num_files - 1] = strdup(tmp); - tmp[0] = 0; - i = 0; - } - } + 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++; - sel->files = realloc(sel->files, sel->num_files * sizeof(char *)); - sel->files[sel->num_files - 1] = strdup(tmp); + 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); + if (tmp) free(tmp); + if (_data) free(_data); - ECORE_X_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES; - ECORE_X_SELECTION_DATA(sel)->length = sel->num_files; + ECORE_XCB_SELECTION_DATA(sel)->content = ECORE_X_SELECTION_CONTENT_FILES; + ECORE_XCB_SELECTION_DATA(sel)->length = sel->num_files; - return ECORE_X_SELECTION_DATA(sel); + return ECORE_XCB_SELECTION_DATA(sel); } -static int -_ecore_x_selection_data_files_free(void *data) +static void * +_ecore_xcb_selection_parser_targets(const char *target __UNUSED__, + void *data, + int size, + int format __UNUSED__) { - Ecore_X_Selection_Data_Files *sel; - int i; + Ecore_X_Selection_Data_Targets *sel; + unsigned long *targets; + int i = 0; - sel = data; - if (sel->files) - { - for (i = 0; i < sel->num_files; i++) - free(sel->files[i]); - free(sel->files); - } - free(sel); - return 0; -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -static void * -_ecore_x_selection_parser_text(const char *target __UNUSED__, - void *_data, - int size, - int format __UNUSED__) -{ - Ecore_X_Selection_Data_Text *sel; - char *data = _data; + if (!(targets = (unsigned long *)data)) return NULL; - sel = calloc(1, sizeof(Ecore_X_Selection_Data_Text)); + sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets)); + if (!sel) return NULL; - if (data[size - 1]) + sel->num_targets = (size - 2); + sel->targets = malloc((size - 2) * sizeof(char *)); + if (!sel->targets) { - /* Isn't nul terminated */ - size++; - data = realloc(data, size); - data[size - 1] = 0; + 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); + } } - 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)->free = _ecore_x_selection_data_text_free; + 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_x_selection_data_text_free(void *data) +_ecore_xcb_selection_data_text_free(void *data) { Ecore_X_Selection_Data_Text *sel; - sel = data; - free(sel->text); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(sel = data)) return 0; + if (sel->text) 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__) +static int +_ecore_xcb_selection_data_targets_free(void *data) { Ecore_X_Selection_Data_Targets *sel; - uint32_t *targets; - xcb_get_atom_name_cookie_t *cookies; - int i; - sel = calloc(1, sizeof(Ecore_X_Selection_Data_Targets)); - targets = (uint32_t *)data; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - sel->num_targets = size - 2; - sel->targets = malloc((size - 2) * sizeof(char *)); - cookies = (xcb_get_atom_name_cookie_t *)malloc ((size - 2) * sizeof (xcb_get_atom_name_cookie_t)); - for (i = 0; i < size - 2; i++) - cookies[i] = xcb_get_atom_name_unchecked(_ecore_xcb_conn, targets[i + 2]); - - /* FIXME: do we let the declaration of reply inside the loop ? */ - for (i = 0; i < size - 2; i++) - { - xcb_get_atom_name_reply_t *reply; - char *name; - int length; - - reply =xcb_get_atom_name_reply(_ecore_xcb_conn, cookies[i], NULL); - length = xcb_get_atom_name_name_length(reply); - name = (char *)malloc (length + 1); - memcpy(name, xcb_get_atom_name_name(reply), length); - name[length] = '\0'; - sel->targets[i - 2] = name; - } - free(cookies); - free(data); - - 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; - return sel; + 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_x_selection_data_targets_free(void *data) +_ecore_xcb_selection_data_files_free(void *data) { - Ecore_X_Selection_Data_Targets *sel; - int i; + Ecore_X_Selection_Data_Files *sel; - sel = data; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (sel->targets) + if (!(sel = data)) return 0; + if (sel->files) { - for (i = 0; i < sel->num_targets; i++) - free(sel->targets[i]); - free(sel->targets); + 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 index a85b2b7..913f199 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_shape.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_shape.c @@ -1,290 +1,50 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" - - -/** - * @defgroup Ecore_X_Shape_Group X Shape extension - * - * Functions that use the shape extension of the X server to change shape of given windows. - */ - - #ifdef ECORE_XCB_SHAPE -static int _shape_available = 0; -static xcb_shape_query_version_cookie_t _ecore_xcb_shape_init_cookie; -#endif /* ECORE_XCB_SHAPE */ +# include +#endif - -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_shape_init and - _ecore_xcb_shape_init_finalize. The first one gets the cookies and - the second one gets the replies. */ +/* external variables */ +int _ecore_xcb_event_shape = -1; void -_ecore_x_shape_init(const xcb_query_extension_reply_t *reply) -{ -#ifdef ECORE_XCB_SHAPE - if (reply && (reply->present)) - _ecore_xcb_shape_init_cookie = xcb_shape_query_version_unchecked(_ecore_xcb_conn); -#endif /* ECORE_XCB_SHAPE */ -} - -void -_ecore_x_shape_init_finalize(void) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_query_version_reply_t *reply; - - reply = xcb_shape_query_version_reply(_ecore_xcb_conn, - _ecore_xcb_shape_init_cookie, - NULL); - if (reply) - { - _shape_available = 1; - free(reply); - } -#endif /* ECORE_XCB_SHAPE */ -} - - -/** - * Sets the shape of the given window to the given pixmap. - * @param dest_win The given window. - * @param source_mask A 2-bit depth pixmap that provides the new shape of the window. - * - * Sets the shape of the window @p dest_win to the pixmap @p source_mask. - * @ingroup Ecore_X_Shape_Group - */ -EAPI void -ecore_x_window_shape_mask_set(Ecore_X_Window dest_win, - Ecore_X_Pixmap source_mask) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_mask(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, dest_win, 0, 0, source_mask); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_window_set(Ecore_X_Window dest_win, - Ecore_X_Window shape_win) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, dest_win, 0, 0, shape_win); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_window_set_xy(Ecore_X_Window dest_win, - Ecore_X_Window shape_win, - int x, - int y) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, dest_win, x, y, shape_win); -#endif /* ECORE_XCB_SHAPE */ -} - - -/** - * Sets the shape of the given window to a rectangle. - * @param dest_win The given window. - * @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. - * - * Sets the shape of the window @p dest_win to a rectangle defined by - * @p x, @p y, @p width and @p height. - * @ingroup Ecore_X_Shape_Group - */ -EAPI void -ecore_x_window_shape_rectangle_set(Ecore_X_Window dest_win, - int x, - int y, - int width, - int height) -{ -#ifdef ECORE_XCB_SHAPE - xcb_rectangle_t rect; - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, 0, dest_win, 0, 0, 1, &rect); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_rectangles_set(Ecore_X_Window dest_win, - Ecore_X_Rectangle *rects, - int num) +_ecore_xcb_shape_init(void) { -#ifdef ECORE_XCB_SHAPE - if (num > 0) - xcb_shape_rectangles(_ecore_xcb_conn, - XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, - 0, dest_win, 0, 0, num, (xcb_rectangle_t *)rects); - else - xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, 0, dest_win, 0, 0, 0, NULL); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_window_add(Ecore_X_Window dest_win, - Ecore_X_Window shape_win) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, dest_win, 0, 0, shape_win); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_window_add_xy(Ecore_X_Window dest_win, - Ecore_X_Window shape_win, - int x, - int y) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_combine(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, XCB_SHAPE_SK_BOUNDING, dest_win, x, y, shape_win); -#endif /* ECORE_XCB_SHAPE */ -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); -EAPI void -ecore_x_window_shape_rectangle_add(Ecore_X_Window dest_win, - int x, - int y, - int width, - int height) -{ -#ifdef ECORE_XCB_SHAPE - xcb_rectangle_t rect; - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, 0, dest_win, 0, 0, 1, &rect); -#endif /* ECORE_XCB_SHAPE */ -} - -EAPI void -ecore_x_window_shape_rectangle_clip(Ecore_X_Window dest_win, - int x, - int y, - int width, - int height) -{ - xcb_rectangle_t rect; - - rect.x = x; - rect.y = y; - rect.width = width; - rect.height = height; - xcb_shape_rectangles(_ecore_xcb_conn, - XCB_SHAPE_SO_INTERSECT, XCB_SHAPE_SK_BOUNDING, - 0, dest_win, 0, 0, 1, &rect); -} - -EAPI void -ecore_x_window_shape_rectangles_add(Ecore_X_Window dest_win, - Ecore_X_Rectangle *rects, - int num) -{ #ifdef ECORE_XCB_SHAPE - if (num > 0) - xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, 0, dest_win, 0, 0, num, (const xcb_rectangle_t *)rects); - else - xcb_shape_rectangles(_ecore_xcb_conn, XCB_SHAPE_SO_UNION, XCB_SHAPE_SK_BOUNDING, 0, dest_win, 0, 0, 0, NULL); -#endif /* ECORE_XCB_SHAPE */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_shape_id); +#endif } - -/** - * Sends the ShapeGetRectangles request. - * @param window Requested window. - * @ingroup Ecore_X_Shape_Group - */ -EAPI void -ecore_x_window_shape_rectangles_get_prefetch(Ecore_X_Window window) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_get_rectangles_cookie_t cookie; - - cookie = xcb_shape_get_rectangles_unchecked(_ecore_xcb_conn, window, XCB_SHAPE_SK_BOUNDING); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_SHAPE */ -} - - -/** - * Gets the reply of the ShapeGetRectangles request sent by ecore_x_window_shape_rectangles_get_prefetch(). - * @ingroup Ecore_X_Shape_Group - */ -EAPI void -ecore_x_window_shape_rectangles_get_fetch(void) +void +_ecore_xcb_shape_finalize(void) { #ifdef ECORE_XCB_SHAPE - xcb_shape_get_rectangles_cookie_t cookie; - xcb_shape_get_rectangles_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_shape_get_rectangles_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_SHAPE */ -} + const xcb_query_extension_reply_t *ext_reply; +#endif + LOGFN(__FILE__, __LINE__, __FUNCTION__); -/** - * To document. - * @param window Unused. - * @param num_ret To document. - * @return To document. - * - * To use this function, you must call before, and in order, - * ecore_x_window_shape_rectangles_get_prefetch(), which sends the ShapeGetRectangles request, - * then ecore_x_window_shape_rectangles_get_fetch(), which gets the reply. - * @ingroup Ecore_X_Shape_Group - */ -EAPI Ecore_X_Rectangle * -ecore_x_window_shape_rectangles_get(Ecore_X_Window window __UNUSED__, - int *num_ret) -{ - Ecore_X_Rectangle *rects = NULL; - uint32_t num = 0; #ifdef ECORE_XCB_SHAPE - xcb_shape_get_rectangles_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply) + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_shape_id); + if ((ext_reply) && (ext_reply->present)) { - if (num_ret) *num_ret = 0; - return NULL; + 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; } - - num = reply->rectangles_len; - rects = malloc(sizeof(Ecore_X_Rectangle) * num); - if (rects) - memcpy (rects, - xcb_shape_get_rectangles_rectangles(reply), - num * sizeof (Ecore_X_Rectangle)); - else - num = 0; -#endif /* ECORE_XCB_SHAPE */ - - if (num_ret) *num_ret = num; - - return rects; +#endif } -EAPI void -ecore_x_window_shape_events_select(Ecore_X_Window dest_win, - int on) -{ -#ifdef ECORE_XCB_SHAPE - xcb_shape_select_input(_ecore_xcb_conn, dest_win, on ? 1 : 0); -#endif /* ECORE_XCB_SHAPE */ -} diff --git a/src/lib/ecore_x/xcb/ecore_xcb_sync.c b/src/lib/ecore_x/xcb/ecore_xcb_sync.c index 5b1fd0b..75f4e4f 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_sync.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_sync.c @@ -1,137 +1,338 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" +# ifdef ECORE_XCB_SYNC +# include +# endif +/* local variables */ +static Eina_Bool _sync_avail = EINA_FALSE; -/** - * @defgroup Ecore_X_Sync_Group X Sync Extension Functions - * - * Functions related to the X Sync extension. - */ - - -#ifdef ECORE_XCB_SYNC -static int _sync_available = 0; -static xcb_sync_initialize_cookie_t _ecore_xcb_sync_init_cookie; -#endif /* ECORE_XCB_SYNC */ - - -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_sync_init and - _ecore_xcb_sync_init_finalize. The first one gets the cookies and - the second one gets the replies and set the atoms. */ +/* external variables */ +int _ecore_xcb_event_sync = -1; void -_ecore_x_sync_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_sync_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_SYNC - if (reply && (reply->present)) - _ecore_xcb_sync_init_cookie = xcb_sync_initialize_unchecked(_ecore_xcb_conn, - XCB_SYNC_MAJOR_VERSION, - XCB_SYNC_MINOR_VERSION); -#endif /* ECORE_XCB_SYNC */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_sync_id); +#endif } void -_ecore_x_sync_init_finalize(void) +_ecore_xcb_sync_finalize(void) { #ifdef ECORE_XCB_SYNC - xcb_sync_initialize_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_sync_initialize_reply(_ecore_xcb_conn, - _ecore_xcb_sync_init_cookie, NULL); + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (reply) +#ifdef ECORE_XCB_SYNC + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_sync_id); + if ((ext_reply) && (ext_reply->present)) { - if (reply->major_version >= 3) - _sync_available = 1; - free(reply); + 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 /* ECORE_XCB_SYNC */ +#endif } - -/** - * Return whether the X server supports the Sync Extension. - * @return 1 if the X Sync Extension is available, 0 otherwise. - * - * Return 1 if the X server supports the Sync Extension version 3.0, - * 0 otherwise. - * @ingroup Ecore_X_Sync_Group - */ -EAPI int -ecore_x_sync_query(void) +void +_ecore_xcb_sync_magic_send(int val, + Ecore_X_Window win) { -#ifdef ECORE_XCB_SYNC - return _sync_available; -#else - return 0; -#endif /* ECORE_XCB_SYNC */ -} + 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; -/** - * Create a new alarm. - * @param counter A counter. - * @return A newly created alarm. - * - * Create a new alarm. - * @ingroup Ecore_X_Sync_Group - */ + 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 value_list[6]; - xcb_sync_int64_t init; + uint32_t list[6], mask; + xcb_sync_int64_t init; Ecore_X_Sync_Alarm alarm; - uint32_t value_mask; +#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); - value_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; - value_list[0] = counter; - value_list[1] = XCB_SYNC_VALUETYPE_ABSOLUTE; - value_list[2] = 1; - value_list[3] = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON; - value_list[4] = 1; - value_list[5] = 1; + 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, - value_mask, - (const uint32_t *)value_list); - ecore_x_sync(); + xcb_sync_create_alarm(_ecore_xcb_conn, alarm, mask, list); + ecore_x_sync(); // needed + return alarm; -#else +#endif return 0; -#endif /* ECORE_XCB_SYNC */ } - -/** - * Delete an alarm. - * @param alarm The alarm to delete. - * @return 1 on success, 0 otherwise. - * - * Delete the @p alarm. Returns 1 on success, 0 otherwise. - * @ingroup Ecore_X_Sync_Group - */ -EAPI int +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); - return 1; -#else +// 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; -#endif /* ECORE_XCB_SYNC */ } + +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 index b02eb7a..8e38c5a 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_window.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_window.c @@ -1,33 +1,48 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -#include "Ecore.h" #include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" - - -static int ignore_num = 0; -static Ecore_X_Window *ignore_list = NULL; - -static Ecore_X_Window _ecore_x_window_at_xy_get(Ecore_X_Window base, - int16_t base_x, - int16_t base_y, - int16_t x, - int16_t y, - Ecore_X_Window *skip, - int skip_num); - #ifdef ECORE_XCB_RENDER -static Ecore_X_Window _ecore_x_window_argb_internal_new(Ecore_X_Window parent, - int16_t x, - int16_t y, - uint16_t w, - uint16_t h, - uint8_t override_redirect, - uint8_t save_under); -#endif /* 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 @@ -50,49 +65,53 @@ EAPI Ecore_X_Window ecore_x_window_new(Ecore_X_Window parent, int x, int y, - int width, - int height) -{ - uint32_t value_list[9]; - Ecore_X_Window window; - xcb_visualid_t vis = { XCB_WINDOW_CLASS_COPY_FROM_PARENT }; - uint32_t value_mask; - - if (parent == 0) parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - 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; - - value_list[0] = XCB_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] = 0; - value_list[6] = 0; - 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; - - window = xcb_generate_id(_ecore_xcb_conn); - xcb_create_window(_ecore_xcb_conn, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, - window, parent, x, y, width, height, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - vis, - value_mask, - value_list); - - if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root) ecore_x_window_defaults_set(window); - return window; + 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; } /** @@ -110,47 +129,50 @@ EAPI Ecore_X_Window ecore_x_window_override_new(Ecore_X_Window parent, int x, int y, - int width, - int height) -{ - uint32_t value_list[9]; - Ecore_X_Window window; - xcb_visualid_t vis = { XCB_WINDOW_CLASS_COPY_FROM_PARENT }; - uint32_t value_mask; - - if (parent == 0) parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - 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; - - value_list[0] = XCB_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] = 1; - value_list[6] = 0; - 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; - - window = xcb_generate_id(_ecore_xcb_conn); - xcb_create_window(_ecore_xcb_conn, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, - window, parent, x, y, width, height, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - vis, - value_mask, - value_list); - return window; + 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; } /** @@ -168,43 +190,42 @@ EAPI Ecore_X_Window ecore_x_window_input_new(Ecore_X_Window parent, int x, int y, - int width, - int height) -{ - uint32_t value_list[3]; - Ecore_X_Window window; - xcb_visualid_t vis = { XCB_WINDOW_CLASS_COPY_FROM_PARENT }; - uint32_t value_mask; - - if (parent == 0) parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - value_mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_DONT_PROPAGATE; - - value_list[0] = 1; - value_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; - value_list[2] = XCB_EVENT_MASK_NO_EVENT; - - window = xcb_generate_id(_ecore_xcb_conn); - xcb_create_window(_ecore_xcb_conn, - XCB_WINDOW_CLASS_COPY_FROM_PARENT, - window, parent, x, y, width, height, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - vis, - value_mask, - value_list); + int w, + int h) +{ + Ecore_X_Window win; + uint32_t mask, mask_list[3]; - if (parent == ((xcb_screen_t *)_ecore_xcb_screen)->root) - { - } + LOGFN(__FILE__, __LINE__, __FUNCTION__) + CHECK_XCB_CONN; - return window; + 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; } /** @@ -213,27 +234,25 @@ ecore_x_window_input_new(Ecore_X_Window parent, * window of the default display is used. * @param x X position. * @param y Y position. - * @param width Width. - * @param height Height. - * @return The new window handle. + * @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 width, - int height) + int w, + int h) { - Ecore_X_Window window = 0; + Ecore_X_Window win = 0; -#ifdef ECORE_XCB_RENDER - window = _ecore_x_window_argb_internal_new(parent, - x, y, width, height, - 1, 0); -#endif /* ECORE_XCB_RENDER */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); - return window; + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0); + + return win; } /** @@ -242,27 +261,25 @@ ecore_x_window_manager_argb_new(Ecore_X_Window parent, * window of the default display is used. * @param x X position. * @param y Y position. - * @param width Width. - * @param height Height. - * @return The new window handle. + * @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 width, - int height) + int w, + int h) { - Ecore_X_Window window = 0; + Ecore_X_Window win = 0; -#ifdef ECORE_XCB_RENDER - window = _ecore_x_window_argb_internal_new(parent, - x, y, width, height, - 0, 0); -#endif /* ECORE_XCB_RENDER */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); - return window; + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 0, 0); + + return win; } /** @@ -271,27 +288,25 @@ ecore_x_window_argb_new(Ecore_X_Window parent, * window of the default display is used. * @param x X position. * @param y Y position. - * @param width Width. - * @param height Height. - * @return The new window handle. + * @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 width, - int height) + int w, + int h) { - Ecore_X_Window window = 0; + Ecore_X_Window win = 0; -#ifdef ECORE_XCB_RENDER - window = _ecore_x_window_argb_internal_new(parent, - x, y, width, height, - 1, 0); -#endif /* ECORE_XCB_RENDER */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); - return window; + win = _ecore_xcb_window_argb_internal_new(parent, x, y, w, h, 1, 0); + + return win; } /** @@ -302,283 +317,331 @@ ecore_x_window_override_argb_new(Ecore_X_Window parent, /** * Deletes the given window. - * @param window The given window. + * @param win The given window. * @ingroup Ecore_X_Window_Destroy_Group */ EAPI void -ecore_x_window_del(Ecore_X_Window window) +ecore_x_window_free(Ecore_X_Window win) { - /* sorry sir, deleting the root window doesn't sound like - * a smart idea. - */ - if (window) - xcb_destroy_window(_ecore_xcb_conn, window); + 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 window 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 window) +ecore_x_window_delete_request_send(Ecore_X_Window win) { - xcb_client_message_event_t ev; - - /* sorry sir, deleting the root window doesn't sound like - * a smart idea. - */ - if (window == 0) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - ev.response_type = XCB_CLIENT_MESSAGE; - ev.format = 32; - ev.sequence = 0; - ev.window = window; - ev.type = ECORE_X_ATOM_WM_PROTOCOLS; - ev.data.data32[0] = ECORE_X_ATOM_WM_DELETE_WINDOW; - ev.data.data32[1] = XCB_CURRENT_TIME; - - xcb_send_event(_ecore_xcb_conn, 0, window, - XCB_EVENT_MASK_NO_EVENT, (const char *)&ev); + 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); } -/** - * @defgroup Ecore_X_Window_Configure_Group X Window Configure Functions - * - * Functions to configure X windows. - */ - - -/** - * Configures the given window with the given mask. - * @param window The given window. - * @param mask The given mask. - * @param x The X coordinate of the window. - * @param y The Y coordinate of the window. - * @param width The width of the window. - * @param height The height of the window. - * @param border_width The border width of the window. - * @param sibling The sibling window of the window. - * @param stack_mode The stack mode of the window. - * @ingroup Ecore_X_Window_Configure_Group - */ EAPI void -ecore_x_window_configure(Ecore_X_Window window, +ecore_x_window_configure(Ecore_X_Window win, Ecore_X_Window_Configure_Mask mask, int x, int y, - int width, - int height, + int w, + int h, int border_width, Ecore_X_Window sibling, int stack_mode) { - uint32_t *value_list; - uint32_t value_mask; - int length = 0; - - if (!window) - return; - - value_mask = mask; - for ( ; value_mask; value_mask >>= 1) - if (value_mask & 1) - length++; - value_list = (uint32_t *)malloc(sizeof(uint32_t) * length); - if (!value_list) - return; - - value_mask = mask; - for ( ; value_mask; value_mask >>= 1, value_list++) - if (value_mask & 1) - { - switch (value_mask) { - case XCB_CONFIG_WINDOW_X: - *value_list = x; - break; - case XCB_CONFIG_WINDOW_Y: - *value_list = y; - break; - case XCB_CONFIG_WINDOW_WIDTH: - *value_list = width; - break; - case XCB_CONFIG_WINDOW_HEIGHT: - *value_list = height; - break; - case XCB_CONFIG_WINDOW_BORDER_WIDTH: - *value_list = border_width; - break; - case XCB_CONFIG_WINDOW_SIBLING: - *value_list = sibling; - break; - case XCB_CONFIG_WINDOW_STACK_MODE: - *value_list = stack_mode; - break; - } - } + 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, window, mask, value_list); - free(value_list); + 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 window The window to move. - * @param x X position. - * @param y Y position. - * @ingroup Ecore_X_Window_Configure_Group + * @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 window, +ecore_x_window_move(Ecore_X_Window win, int x, int y) { - uint32_t value_list[2]; - uint32_t value_mask; + uint32_t list[2], mask; - if (!window) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y; + if (!win) return; - value_list[0] = x; - value_list[1] = y; + mask = (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y); + list[0] = x; + list[1] = y; - xcb_configure_window(_ecore_xcb_conn, window, value_mask, value_list); + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); } /** * Resizes a window. - * @param window The window to resize. - * @param width New width of the window. - * @param height New height of the window. - * @ingroup Ecore_X_Window_Configure_Group + * @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 window, - int width, - int height) +ecore_x_window_resize(Ecore_X_Window win, + int w, + int h) { - uint32_t value_list[2]; - uint32_t value_mask; + uint32_t list[2], mask; - if (!window) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (width < 1) width = 1; - if (height < 1) height = 1; + if (!win) return; + if (w < 1) w = 1; + if (h < 1) h = 1; - value_mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + mask = (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT); + list[0] = w; + list[1] = h; - value_list[0] = width; - value_list[1] = height; - - xcb_configure_window(_ecore_xcb_conn, window, value_mask, value_list); + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); } /** * Moves and resizes a window. - * @param window The window to move and resize. - * @param x New X position of the window. - * @param y New Y position of the window. - * @param width New width of the window. - * @param height New height of the window. - * @ingroup Ecore_X_Window_Configure_Group + * @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 window, +ecore_x_window_move_resize(Ecore_X_Window win, int x, int y, - int width, - int height) + int w, + int h) { - uint32_t value_list[4]; - uint32_t value_mask; + uint32_t list[4], mask; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (!window) - return; + if (!win) return; + if (w < 1) w = 1; + if (h < 1) h = 1; - if (width < 1) width = 1; - if (height < 1) height = 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; - value_mask = - XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | - XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + xcb_configure_window(_ecore_xcb_conn, win, mask, + (const uint32_t *)&list); +// ecore_x_flush(); +} - value_list[0] = x; - value_list[1] = y; - value_list[2] = width; - value_list[3] = height; +/** + * 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__); - xcb_configure_window(_ecore_xcb_conn, window, value_mask, value_list); + if (!win) return 0; + return ecore_x_drawable_border_width_get(win); } /** * Sets the width of the border of the given window. - * @param window The given window. - * @param border_width The new border width. - * @ingroup Ecore_X_Window_Configure_Group + * @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 window, +ecore_x_window_border_width_set(Ecore_X_Window win, int border_width) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* doesn't make sense to call this on a root window */ - if (!window) - return; + if (!win) return; - value_list = border_width; + list = border_width; - xcb_configure_window(_ecore_xcb_conn, window, XCB_CONFIG_WINDOW_BORDER_WIDTH, &value_list); + 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 window The window to raise. - * @ingroup Ecore_X_Window_Configure_Group + * @param win The window to raise. + * @ingroup Ecore_X_Window_Z_Order_Group */ EAPI void -ecore_x_window_raise(Ecore_X_Window window) +ecore_x_window_raise(Ecore_X_Window win) { - uint32_t value_list; + uint32_t list[] = { XCB_STACK_MODE_ABOVE }; - if (!window) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_list = XCB_STACK_MODE_ABOVE; - - xcb_configure_window(_ecore_xcb_conn, window, XCB_CONFIG_WINDOW_STACK_MODE, &value_list); + xcb_configure_window(_ecore_xcb_conn, win, + XCB_CONFIG_WINDOW_STACK_MODE, list); +// ecore_x_flush(); } /** * Lowers the given window. - * @param window The window to lower. - * @ingroup Ecore_X_Window_Configure_Group + * @param win The window to lower. + * @ingroup Ecore_X_Window_Z_Order_Group */ EAPI void -ecore_x_window_lower(Ecore_X_Window window) +ecore_x_window_lower(Ecore_X_Window win) { - uint32_t value_list; + uint32_t list[] = { XCB_STACK_MODE_BELOW }; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (!window) - return; + xcb_configure_window(_ecore_xcb_conn, win, + XCB_CONFIG_WINDOW_STACK_MODE, list); +// ecore_x_flush(); +} - value_list = XCB_STACK_MODE_BELOW; +/** + * 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__); - xcb_configure_window(_ecore_xcb_conn, window, XCB_CONFIG_WINDOW_STACK_MODE, &value_list); + return ecore_x_drawable_depth_get(win); } /** - * @defgroup Evas_X_Window_Change_Properties_Group X Window Change Property Functions + * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions * - * Functions that change window properties. + * Functions that set window properties. */ /** @@ -587,47 +650,37 @@ ecore_x_window_lower(Ecore_X_Window window) * The default properties set for the window are @c WM_CLIENT_MACHINE and * @c _NET_WM_PID. * - * @param window The given window. - * @ingroup Ecore_X_Window_Change_Property_Group + * @param win The given window. + * @ingroup Ecore_X_Window_Properties_Group */ EAPI void -ecore_x_window_defaults_set(Ecore_X_Window window) -{ - char buf[MAXHOSTNAMELEN]; - pid_t pid; - int argc; - char **argv; - - /* - * Set WM_CLIENT_MACHINE. - */ - gethostname(buf, MAXHOSTNAMELEN); - buf[MAXHOSTNAMELEN - 1] = '\0'; - /* The ecore function uses UTF8 which Xlib may not like (especially - * with older clients) */ - /* ecore_xcb_window_prop_string_set(win, ECORE_X_ATOM_WM_CLIENT_MACHINE, - (char *)buf); */ - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - ECORE_X_ATOM_WM_CLIENT_MACHINE, - ECORE_X_ATOM_STRING, - 8, strlen(buf), buf); - - /* - * Set _NET_WM_PID - */ - pid = getpid(); - ecore_x_netwm_pid_set(window, pid); +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; - ecore_x_netwm_window_type_set(window, ECORE_X_WINDOW_TYPE_NORMAL); + 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(window, argc, argv); + ecore_x_icccm_command_set(win, argc, argv); } /** * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions * - * Functions to change the visibility of X windows. + * Functions to access and change the visibility of X windows. */ /** @@ -635,13 +688,17 @@ ecore_x_window_defaults_set(Ecore_X_Window window) * * Synonymous to "mapping" a window in X Window System terminology. * - * @param window The window to show. - * @ingroup Ecore_X_Window_Visibility_Group + * @param win The window to show. + * @ingroup Ecore_X_Window_Visibility */ EAPI void -ecore_x_window_show(Ecore_X_Window window) +ecore_x_window_show(Ecore_X_Window win) { - xcb_map_window(_ecore_xcb_conn, window); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (win) + xcb_map_window(_ecore_xcb_conn, win); } /** @@ -649,943 +706,921 @@ ecore_x_window_show(Ecore_X_Window window) * * Synonymous to "unmapping" a window in X Window System terminology. * - * @param window The window to hide. - * @ingroup Ecore_X_Window_Visibility_Group + * @param win The window to hide. + * @ingroup Ecore_X_Window_Visibility */ EAPI void -ecore_x_window_hide(Ecore_X_Window window) +ecore_x_window_hide(Ecore_X_Window win) { - xcb_unmap_notify_event_t ev; - Ecore_X_Window root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* ICCCM: SEND unmap event... */ - root = window; - /* FIXME: is it correct ? */ - if (xcb_setup_roots_iterator(xcb_get_setup(_ecore_xcb_conn)).rem == 1) - root = ((xcb_screen_t *)_ecore_xcb_screen)->root; - else + if (win) { - xcb_get_geometry_cookie_t cookie; - xcb_get_geometry_reply_t *rep; - Ecore_X_Drawable draw; - - /* FIXME: can we avoid round trips, here ? */ - draw = window; - cookie = xcb_get_geometry_unchecked(_ecore_xcb_conn, draw); - rep = xcb_get_geometry_reply(_ecore_xcb_conn, cookie, NULL); - if (!rep) - return; - root = rep->root; - free(rep); - } - ev.response_type = XCB_UNMAP_NOTIFY; - ev.pad0 = 0; - ev.sequence = 0; - ev.event = root; - ev.window = window; - ev.from_configure = 0; + 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, window); + 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_Input_Focus_Group X Window Input Focus Functions + * @defgroup Ecore_X_Window_Focus_Functions X Window Focus Functions * - * Functions that manage the focus of an X Window. + * Functions that give the focus to an X Window. */ /** - * Sets the focus to the window @p window. - * @param window The window to focus. - * @ingroup Ecore_X_Window_Input_Focus_Group + * 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 window) +ecore_x_window_focus(Ecore_X_Window win) { - Ecore_X_Time time = XCB_CURRENT_TIME; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; - /* xcb_set_input_focus(_ecore_xcb_conn, XCB_INPUT_FOCUS_NONE, win, time); */ xcb_set_input_focus(_ecore_xcb_conn, - XCB_INPUT_FOCUS_POINTER_ROOT, window, time); + XCB_INPUT_FOCUS_PARENT, win, XCB_CURRENT_TIME); +// ecore_x_flush(); } /** * Sets the focus to the given window at a specific time. - * @param window The window to focus. - * @param time When to set the focus to the window. - * @ingroup Ecore_X_Window_Input_Focus_Group + * @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 window, - Ecore_X_Time time) +ecore_x_window_focus_at_time(Ecore_X_Window win, + Ecore_X_Time time __UNUSED__) { - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* xcb_set_input_focus(_ecore_xcb_conn, XCB_INPUT_FOCUS_NONE, win, time); */ - xcb_set_input_focus(_ecore_xcb_conn, - XCB_INPUT_FOCUS_POINTER_ROOT, window, time); + 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_Reparent_Group X Window Reparent Functions + * @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 window The window to reparent. + * @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_Reparent_Group + * @ingroup Ecore_X_Window_Parent_Group */ EAPI void -ecore_x_window_reparent(Ecore_X_Window window, - Ecore_X_Window new_parent, +ecore_x_window_reparent(Ecore_X_Window win, + Ecore_X_Window parent, int x, int y) { - if (new_parent == 0) new_parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - xcb_reparent_window(_ecore_xcb_conn, window, new_parent, x, y); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + if (parent == 0) + parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; -/** - * @defgroup Ecore_X_Window_Change_Attributes_Group X Window Change Attributes Functions - * - * Functions that change the attributes of a window. - */ + xcb_reparent_window(_ecore_xcb_conn, win, parent, x, y); +// ecore_x_flush(); +} -/** - * Sets the background pixmap of the given window. - * @param window The given window. - * @param pixmap The pixmap to set to. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_pixmap_set(Ecore_X_Window window, +ecore_x_window_pixmap_set(Ecore_X_Window win, Ecore_X_Pixmap pixmap) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_list = pixmap; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_BACK_PIXMAP, &value_list); + 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 window The given window. - * @param red The red component of the color to set to. - * @param green The green component of the color to set to. - * @param blue The blue component of the color to set to. - * @ingroup Ecore_X_Window_Change_Attributes_Group + * @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 window, +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 *rep; - uint32_t value_list; - - /* FIXME: should I provide a reply, and not the color components, here ? */ - /* (because of roundtrips) */ - cookie = xcb_alloc_color_unchecked(_ecore_xcb_conn, - ((xcb_screen_t *)_ecore_xcb_screen)->default_colormap, - red, green, blue); - rep = xcb_alloc_color_reply(_ecore_xcb_conn, cookie, NULL); - if (!rep) - return; - - value_list = rep->pixel; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_BACK_PIXEL, &value_list); - free(rep); + 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(); } -/** - * Sets the bit gravity of the given window. - * @param window The given window. - * @param gravity The gravity. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_pixel_gravity_set(Ecore_X_Window window, +ecore_x_window_pixel_gravity_set(Ecore_X_Window win, Ecore_X_Gravity gravity) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_list = gravity; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_BIT_GRAVITY, &value_list); + list = gravity; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_BIT_GRAVITY, &list); +// ecore_x_flush(); } -/** - * Sets the gravity of the given window. - * @param window The given window. - * @param gravity The gravity. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_gravity_set(Ecore_X_Window window, +ecore_x_window_gravity_set(Ecore_X_Window win, Ecore_X_Gravity gravity) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_list = gravity; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_WIN_GRAVITY, &value_list); + list = gravity; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_WIN_GRAVITY, &list); +// ecore_x_flush(); } -/** - * Sets the override attribute of the given window. - * @param window The given window. - * @param override_redirect The override_redirect boolean. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_override_set(Ecore_X_Window window, - int override_redirect) +ecore_x_window_override_set(Ecore_X_Window win, + Eina_Bool override) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - value_list = override_redirect; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_OVERRIDE_REDIRECT, &value_list); + list = override; + + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_OVERRIDE_REDIRECT, &list); +// ecore_x_flush(); } /** - * Shows the cursor of the given window. - * @param window The given window. - * @param show If set to @c 0, hide the cursor. Show it otherwise. - * @ingroup Ecore_X_Window_Change_Attributes_Group + * @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 window, - int show) +ecore_x_window_cursor_show(Ecore_X_Window win, + Eina_Bool show) { - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + 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_Drawable draw; - Ecore_X_Pixmap pixmap; - Ecore_X_Pixmap mask; - Ecore_X_GC gc; - xcb_point_t point; - uint32_t value_list; - - draw = window; - pixmap = xcb_generate_id(_ecore_xcb_conn); - xcb_create_pixmap(_ecore_xcb_conn, - 1, pixmap, draw, - 1, 1); - mask = xcb_generate_id(_ecore_xcb_conn); - xcb_create_pixmap(_ecore_xcb_conn, - 1, mask, draw, - 1, 1); - + 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, draw, 0, NULL); - value_list = 0; - xcb_change_gc(_ecore_xcb_conn, gc, XCB_GC_FOREGROUND, &value_list); - - draw = mask; + 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, draw, - gc, 1, &point); - + 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, - pixmap, mask, - 0, 0, 0, - 0, 0, 0, - 0, 0); - value_list = cursor; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_CURSOR, &value_list); + 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, mask); - xcb_free_pixmap(_ecore_xcb_conn, pixmap); + xcb_free_pixmap(_ecore_xcb_conn, m); + xcb_free_pixmap(_ecore_xcb_conn, p); } else { - uint32_t value_list; - - value_list = 0; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_CURSOR, &value_list); + xcb_change_window_attributes(_ecore_xcb_conn, win, + XCB_CW_CURSOR, &list); } +// ecore_x_flush(); } -/** - * Sets the cursor of the given window. - * @param window The given window. - * @param cursor The given cursor. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_cursor_set(Ecore_X_Window window, +ecore_x_window_cursor_set(Ecore_X_Window win, Ecore_X_Cursor cursor) { - uint32_t value_list; + uint32_t list; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + list = cursor; - value_list = cursor; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_CURSOR, &value_list); + xcb_change_window_attributes(_ecore_xcb_conn, win, XCB_CW_CURSOR, &list); +// ecore_x_flush(); } -/** - * Todo - * @param window The given window. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_container_manage(Ecore_X_Window window) +ecore_x_window_container_manage(Ecore_X_Window win) { - uint32_t value_list; + uint32_t list; - value_list = - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_EVENT_MASK, &value_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(); } -/** - * Todo - * @param window The given window. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_client_manage(Ecore_X_Window window) -{ - uint32_t value_list; - - value_list = - XCB_EVENT_MASK_VISIBILITY_CHANGE | -/* XCB_EVENT_MASK_RESIZE_REDIRECT | */ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | - XCB_EVENT_MASK_FOCUS_CHANGE | - XCB_EVENT_MASK_PROPERTY_CHANGE | - XCB_EVENT_MASK_COLOR_MAP_CHANGE; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_EVENT_MASK, &value_list); +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, window, 1); -#endif /* ECORE_XCB_SHAPE */ + xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE); +#endif +// ecore_x_flush(); } -/** - * Todo - * @param window The given window. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_sniff(Ecore_X_Window window) +ecore_x_window_sniff(Ecore_X_Window win) { - uint32_t value_list; + uint32_t list; - value_list = - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | - XCB_EVENT_MASK_PROPERTY_CHANGE; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_EVENT_MASK, &value_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(); } -/** - * Todo - * @param window The given window. - * @ingroup Ecore_X_Window_Change_Attributes_Group - */ EAPI void -ecore_x_window_client_sniff(Ecore_X_Window window) -{ - uint32_t value_list; - - value_list = - 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; - xcb_change_window_attributes(_ecore_xcb_conn, window, - XCB_CW_EVENT_MASK, &value_list); +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, window, 1); -#endif /* ECORE_XCB_SHAPE */ + xcb_shape_select_input(_ecore_xcb_conn, win, EINA_TRUE); +#endif +// ecore_x_flush(); } -/** - * Clears an area of the given window. - * @param window The given window. - * @param x The X coordinate of the area. - * @param y The Y coordinate of the area. - * @param width The width of the area. - * @param height The height of the area. - * @ingroup Ecore_X_Window_Clear_Area_Group - */ EAPI void -ecore_x_window_area_clear(Ecore_X_Window window, +ecore_x_window_area_clear(Ecore_X_Window win, int x, int y, - int width, - int height) + int w, + int h) { - xcb_clear_area(_ecore_xcb_conn, 0, window, x, y, width, height); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + xcb_clear_area(_ecore_xcb_conn, 0, win, x, y, w, h); +// ecore_x_flush(); } -/** - * Exposes an area of the given window. - * @param window The given window. - * @param x The X coordinate of the area. - * @param y The Y coordinate of the area. - * @param width The width of the area. - * @param height The height of the area. - * @ingroup Ecore_X_Window_Clear_Area_Group - */ EAPI void -ecore_x_window_area_expose(Ecore_X_Window window, +ecore_x_window_area_expose(Ecore_X_Window win, int x, int y, - int width, - int height) + int w, + int h) { - xcb_clear_area(_ecore_xcb_conn, 1, window, x, y, width, height); -} - - -/** - * @defgroup Ecore_X_Window_Save_Set_Group X Window Change Save Set Functions - * - * Functions that either inserts or deletes the specified window from - * the client's save-set. - */ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * Inserts the window in the client's save-set. - * @param window The window to insert in the client's save-set. - * @ingroup Ecore_X_Window_Save_Set_Group - */ -EAPI void -ecore_x_window_save_set_add(Ecore_X_Window window) -{ - xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_INSERT, window); + xcb_clear_area(_ecore_xcb_conn, 1, win, x, y, w, h); +// ecore_x_flush(); } -/** - * Deletes the window from the client's save-set. - * @param window The window to delete from the client's save-set. - * @ingroup Ecore_X_Window_Save_Set_Group - */ EAPI void -ecore_x_window_save_set_del(Ecore_X_Window window) +ecore_x_window_save_set_add(Ecore_X_Window win) { - xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_DELETE, window); -} - -/****************************** - * - * Request that have a reply - * - ******************************/ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_INSERT, win); +} -/** - * Sends the GetInputFocus request. - * @ingroup Ecore_X_Window_Input_Focus_Group - */ EAPI void -ecore_x_get_input_focus_prefetch(void) +ecore_x_window_save_set_del(Ecore_X_Window win) { - xcb_get_input_focus_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_input_focus_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); + xcb_change_save_set(_ecore_xcb_conn, XCB_SET_MODE_DELETE, win); } /** - * Gets the reply of the GetInputFocus request sent by ecore_x_get_input_focus_prefetch(). - * @ingroup Ecore_X_Window_Input_Focus_Group + * gets the window that has focus. + * @return The window that has focus. + * @ingroup Ecore_X_Window_Focus_Functions */ -EAPI void -ecore_x_get_input_focus_fetch(void) +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; - cookie.sequence = _ecore_xcb_cookie_get(); + 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); - _ecore_xcb_reply_cache(reply); + if (!reply) return 0; + focus = reply->focus; + free(reply); + return focus; } -/** - * Gets the window that has focus. - * @return The window that has focus. - * - * Returns the window that has the focus. If an error aoocured, @c 0 - * is returned, otherwise the function returns the window that has focus. - * - * To use this function, you must call before, and in order, - * ecore_x_get_input_focus_prefetch(), which sends the GetInputFocus request, - * then ecore_x_get_input_focus_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Input_Focus_Group - */ -EAPI Ecore_X_Window -ecore_x_window_focus_get(void) +EAPI int +ecore_x_window_argb_get(Ecore_X_Window win) { - xcb_get_input_focus_reply_t *reply; - Ecore_X_Window window = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) return window; - - return reply->focus; -} + uint8_t ret = 0; +#ifdef ECORE_XCB_RENDER + Ecore_X_Visual visual; +#endif + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * @defgroup Ecore_X_Window_Get_Attributes_Group X Window Get Attributes Functions - * - * Functions that get the attributes of a window. - */ +// if (!win) return ret; +#ifdef ECORE_XCB_RENDER + /* grab the window's visual */ + visual = _ecore_xcb_window_visual_get(win); -/** - * Sends the GetWindowAttributes request. - * @ingroup Ecore_X_Window_Get_Attributes_Group - */ -EAPI void -ecore_x_get_window_attributes_prefetch(Ecore_X_Window window) -{ - xcb_get_window_attributes_cookie_t cookie; + /* check if this visual supports alpha */ + ret = _ecore_xcb_render_visual_supports_alpha(visual); +#endif - cookie = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); - _ecore_xcb_cookie_cache(cookie.sequence); + return ret; } -/** - * Gets the reply of the GetWindowAttributes request sent by ecore_x_get_window_attributes_prefetch(). - * @ingroup Ecore_X_Window_Get_Attributes_Group - */ -EAPI void -ecore_x_get_window_attributes_fetch(void) +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.sequence = _ecore_xcb_cookie_get(); + cookie = xcb_get_window_attributes(_ecore_xcb_conn, win); reply = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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; } -/** - * Retrieves the attributes of a window. - * @param windows Unused. - * @param att_ret Pointer to an Ecore_X_Window_Attributes - * structure in which the attributes of a window - * are to be stored. - * - * Retrieves the attributes of a window. If - * @p att_ret is @c NULL, the function does nothing. If an error - * occurred, @p att_ret is set to 0. Otherwise, the @p att_ret structure - * is filled with the attributes os the requested window. - * - * To use this function, you must call before, and in order, - * ecore_x_get_window_attributes_prefetch(), which sends the GetWindowAttributes request, - * then ecore_x_get_window_attributes_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Get_Attributes_Group - */ -EAPI int -ecore_x_window_attributes_get(Ecore_X_Window window __UNUSED__, +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; - if (!att_ret) return 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + 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 = 1; - if (reply->map_state == XCB_MAP_STATE_VIEWABLE) att_ret->viewable = 1; - if (reply->override_redirect) att_ret->override = 1; - if (reply->_class == XCB_WINDOW_CLASS_INPUT_ONLY) att_ret->input_only = 1; - if (reply->save_under) att_ret->save_under = 1; + if (reply->map_state != XCB_MAP_STATE_UNMAPPED) + att_ret->visible = 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 = reply->visual; + if (reply->map_state == XCB_MAP_STATE_VIEWABLE) + att_ret->viewable = EINA_TRUE; - return 1; -} + if (reply->override_redirect) + att_ret->override = EINA_TRUE; -/** - * Finds out whether the given window is currently visible. - * @param window Unused. - * @return 1 if the window is visible, otherwise 0. - * - * Finds out whether the given window is currently visible. - * If an error occurred, or if the window is not visible, 0 is - * returned. Otherwise 1 is returned. - * - * To use this function, you must call before, and in order, - * ecore_x_get_window_attributes_prefetch(), which sends the GetWindowAttributes request, - * then ecore_x_get_window_attributes_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Get_Attributes_Group - */ -EAPI int -ecore_x_window_visible_get(Ecore_X_Window window __UNUSED__) -{ - xcb_get_window_attributes_reply_t *reply; + if (reply->_class == XCB_WINDOW_CLASS_INPUT_ONLY) + att_ret->input_only = EINA_TRUE; - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + if (reply->save_under) + att_ret->save_under = EINA_TRUE; - return (reply->map_state == XCB_MAP_STATE_VIEWABLE) ? 1 : 0; + 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; } - /** - * Sends the QueryPointer request. - * @ingroup Ecore_X_Window_Parent_Group + * 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_pointer_xy_get_prefetch(Ecore_X_Window window) +ecore_x_window_size_get(Ecore_X_Window win, + int *width, + int *height) { - xcb_query_pointer_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_query_pointer_unchecked(_ecore_xcb_conn, window); - _ecore_xcb_cookie_cache(cookie.sequence); + if (!win) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; + ecore_x_drawable_geometry_get(win, NULL, NULL, width, height); } /** - * Gets the reply of the QueryPointer request sent by ecore_x_query_pointer_prefetch(). - * @ingroup Ecore_X_Window_Parent_Group + * Set if a window should be ignored. + * @param win The given window. + * @param ignore if to ignore */ EAPI void -ecore_x_pointer_xy_get_fetch(void) +ecore_x_window_ignore_set(Ecore_X_Window win, + int ignore) { - xcb_query_pointer_cookie_t cookie; - xcb_query_pointer_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_query_pointer_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} + int i = 0, j = 0, count = 0; -/** - * Retrieves the coordinates of the pointer. - * @param window Unused. - * @param x The X coordinate of the pointer. - * @param y The Y coordinate of the pointer. - * - * Retrieves the coordinates of the pointer. - * If the window used in - * ecore_x_query_pointer_prefetch() is not on the same screen than - * the root window or if an error occured, @p x and @p y are set - * to 0. Otherwise, they are respectively set to the X and Y - * coordinates of the pointer. - * - * To use this function, you must call before, and in order, - * ecore_x_query_pointer_prefetch(), which sends the QueryPointer request, - * then ecore_x_query_pointer_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Parent_Group - */ -EAPI void -ecore_x_pointer_xy_get(Ecore_X_Window window __UNUSED__, - int *x, - int *y) -{ - xcb_query_pointer_reply_t *reply; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply = _ecore_xcb_reply_get(); - if (!reply) + if (ignore) { - if (x) *x = 0; - if (y) *y = 0; + if (ignore_list) + { + for (i = 0; i < ignore_num; i++) + if (win == ignore_list[i]) return; - 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; + } - if (x) *x = reply->win_x; - if (y) *y = reply->win_y; + ignore_list = + realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window)); + } } - /** - * Sends the QueryTree request. - * @ingroup Ecore_X_Window_Parent_Group + * Get the ignore list + * @param num number of windows in the list + * @return list of windows to ignore */ -EAPI void -ecore_x_query_tree_prefetch(Ecore_X_Window window) +EAPI Ecore_X_Window * +ecore_x_window_ignore_list(int *num) { - xcb_query_tree_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, window); - _ecore_xcb_cookie_cache(cookie.sequence); + if (num) *num = ignore_num; + return ignore_list; } /** - * Gets the reply of the QueryTree request sent by ecore_x_query_tree_prefetch(). - * @ingroup Ecore_X_Window_Parent_Group + * 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 void -ecore_x_query_tree_fetch(void) +EAPI Ecore_X_Window * +ecore_x_window_root_list(int *num_ret) { - xcb_query_tree_cookie_t cookie; - xcb_query_tree_reply_t *reply; + 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.sequence = _ecore_xcb_cookie_get(); - reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(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; -/** - * Retrieves the parent window of the given window. - * @param window Unused. - * @return The parent window of @p window. - * - * Retrieves the parent window of the given window. If - * an error occured, @c 0 is returned. - * - * To use this function, you must call before, and in order, - * ecore_x_query_tree_prefetch(), which sends the QueryTree request, - * then ecore_x_query_tree_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Parent_Group - */ -EAPI Ecore_X_Window -ecore_x_window_parent_get(Ecore_X_Window window __UNUSED__) -{ - xcb_query_tree_reply_t *reply; + 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; - reply = _ecore_xcb_reply_get(); - if (!reply) return 0; + 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; - return reply->parent; -} + 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; +} -/** - * Retrieves the children windows of the given window. - * @param window Unused. - * @param num children windows count. - * @return The children windows. - * - * Retrieves the children windows of the given window. If - * an error occured, @c 0 is returned. - * - * To use this function, you must call before, and in order, - * ecore_x_query_tree_prefetch(), which sends the QueryTree request, - * then ecore_x_query_tree_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Parent_Group - */ EAPI Ecore_X_Window * -ecore_x_window_children_get(Ecore_X_Window window __UNUSED__, +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; + Ecore_X_Window *windows = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; if (num) *num = 0; - reply = _ecore_xcb_reply_get(); + cookie = xcb_query_tree_unchecked(_ecore_xcb_conn, win); + reply = xcb_query_tree_reply(_ecore_xcb_conn, cookie, NULL); if (!reply) return NULL; - windows = malloc(reply->children_len); - if (!windows) - return NULL; - if (num) *num = reply->children_len; - memcpy(windows, - xcb_query_tree_children(reply), - sizeof(Ecore_X_Window) * reply->children_len); - - return windows; -} - -/* FIXME: I've tried to remove the round trips. 3 cookies are */ -/* created at the beginning of the function. Because of */ -/* the recursivity of the algo, I can't find better trick */ -static Ecore_X_Window -_ecore_x_window_at_xy_get(Ecore_X_Window base, - int16_t base_x, - int16_t base_y, - int16_t x, - int16_t y, - Ecore_X_Window *skip, - int skip_num) -{ - xcb_window_iterator_t iter_children; - xcb_get_window_attributes_cookie_t cookie_get_window_attributes; - xcb_get_geometry_cookie_t cookie_get_geometry; - xcb_query_tree_cookie_t cookie_query_tree; - xcb_get_window_attributes_reply_t *reply_get_window_attributes; - xcb_get_geometry_reply_t *reply_get_geometry; - xcb_query_tree_reply_t *reply_query_tree; - Ecore_X_Window window = 0; - Ecore_X_Window child = 0; - int16_t win_x; - int16_t win_y; - uint16_t win_width; - uint16_t win_height; - - cookie_get_window_attributes = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, base); - cookie_get_geometry = xcb_get_geometry_unchecked(_ecore_xcb_conn, base); - cookie_query_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, base); - - reply_get_window_attributes = xcb_get_window_attributes_reply(_ecore_xcb_conn, cookie_get_window_attributes, NULL); - if (!reply_get_window_attributes) - { - reply_get_geometry = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_get_geometry, NULL); - if (reply_get_geometry) free(reply_get_geometry); - reply_query_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_query_tree, NULL); - if (reply_query_tree) free(reply_query_tree); - return window; - } - - if (reply_get_window_attributes->map_state != XCB_MAP_STATE_VIEWABLE) - { - free(reply_get_window_attributes); - reply_get_geometry = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_get_geometry, NULL); - if (reply_get_geometry) free(reply_get_geometry); - reply_query_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_query_tree, NULL); - if (reply_query_tree) free(reply_query_tree); - return window; - } - - free(reply_get_window_attributes); - - reply_get_geometry = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_get_geometry, NULL); - if (!reply_get_geometry) - { - reply_query_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_query_tree, NULL); - if (reply_query_tree) free(reply_query_tree); - return window; - } - - win_x = reply_get_geometry->x; - win_y = reply_get_geometry->y; - win_width = reply_get_geometry->width; - win_height = reply_get_geometry->height; - - free(reply_get_geometry); - - win_x += base_x; - win_y += base_y; - - if (!((x >= win_x) && - (y >= win_y) && - (x < (int16_t)(win_x + win_width)) && - (y < (int16_t)(win_y + win_height)))) + if (reply->children_len > 0) { - reply_query_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_query_tree, NULL); - if (reply_query_tree) free(reply_query_tree); - return window; - } + windows = malloc(sizeof(Ecore_X_Window) * reply->children_len); + if (windows) + { + unsigned int i = 0; + xcb_window_t *w; - reply_query_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_query_tree, NULL); - if (!reply_query_tree) - { - if (skip) - { - int i; - - for (i = 0; i < skip_num; i++) - if (base == skip[i]) - return window; - } - return base; + w = xcb_query_tree_children(reply); + for (i = 0; i < reply->children_len; i++) + windows[i] = w[i]; + } } - iter_children = xcb_query_tree_children_iterator(reply_query_tree); - for (; iter_children.rem; xcb_window_next(&iter_children)) - { - if (skip) - { - int j; + free(reply); + return windows; +} - for (j = 0; j < skip_num; j++) - if (*iter_children.data == skip[j]) - continue; - } - child = _ecore_x_window_at_xy_get(*iter_children.data, win_x, win_y, x, y, skip, skip_num); - if (child) - { - free(reply_query_tree); +/** + * 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; - return child; - } - } + /* LOGFN(__FILE__, __LINE__, __FUNCTION__); */ + CHECK_XCB_CONN; - if (skip) - { - int i; - - for (i = 0; i < skip_num; i++) - if (base == skip[i]) - { - /* We return 0. child has an xid equal to 0 */ - free(reply_query_tree); - return child; - } - } + 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); - free(reply_query_tree); + return window; +} - return base; +EAPI Ecore_X_Window +ecore_x_window_root_first_get(void) +{ + return ((xcb_screen_t *)_ecore_xcb_screen)->root; } /** - * @defgroup Ecore_X_Window_Geometry_Group X Window Geometry Functions + * Retrieves the geometry of the given window. * - * Functions that change or retrieve the geometry of X windows. + * 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. + * @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) + int y) { - Ecore_X_Window window; - Ecore_X_Window root; + Ecore_X_Window root, win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* FIXME: Proper function to determine current root/virtual root - * window missing here */ root = ((xcb_screen_t *)_ecore_xcb_screen)->root; ecore_x_grab(); - window = _ecore_x_window_at_xy_get(root, 0, 0, x, y, NULL, 0); + win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, NULL, 0); ecore_x_ungrab(); - return window ? window : root; + return win ? win : root; } /** @@ -1593,429 +1628,611 @@ ecore_x_window_at_xy_get(int x, * but skips the windows in the list. * @param x The given X position. * @param y The given Y position. - * @return The window at that 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) + int y, + Ecore_X_Window *skip, + int skip_num) { - Ecore_X_Window window; - Ecore_X_Window root; + Ecore_X_Window root, win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - /* FIXME: Proper function to determine current root/virtual root - * window missing here */ root = ((xcb_screen_t *)_ecore_xcb_screen)->root; ecore_x_grab(); - window = _ecore_x_window_at_xy_get(root, 0, 0, x, y, skip, skip_num); + win = _ecore_xcb_window_at_xy_get(root, 0, 0, x, y, skip, skip_num); ecore_x_ungrab(); - return window ? window : root; + return win ? win : root; } -/** - * Retrieves the top, visible window at the given location, - * but begins at the @p begin window instead of the root one. - * @param begin The window from which we begin. - * @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_begin_get(Ecore_X_Window begin, int x, int y) { - Ecore_X_Window window; + Ecore_X_Window win = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; ecore_x_grab(); - window = _ecore_x_window_at_xy_get(begin, 0, 0, x, y, NULL, 0); + win = _ecore_xcb_window_at_xy_get(begin, 0, 0, x, y, NULL, 0); ecore_x_ungrab(); - return window ? window : begin; + 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; -/* FIXME: Should I provide the replies (or the cookies), instead of - creating them in the function ? */ -#ifdef ECORE_XCB_RENDER -static Ecore_X_Window -_ecore_x_window_argb_internal_new(Ecore_X_Window parent, - int16_t x, - int16_t y, - uint16_t w, - uint16_t h, - uint8_t override_redirect, - uint8_t save_under) -{ - uint32_t value_list[10]; - xcb_depth_iterator_t iter_depth; - xcb_visualtype_iterator_t iter_visualtype; - xcb_render_query_pict_formats_cookie_t cookie_pict_format; - xcb_render_query_pict_formats_reply_t *rep_pict_format; - Ecore_X_Screen *screen = NULL; - Ecore_X_Window win = { 0 }; - xcb_visualid_t vis = { 0 }; - Ecore_X_Colormap colormap; - uint32_t value_mask; - - cookie_pict_format = xcb_render_query_pict_formats_unchecked(_ecore_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); - if (parent == 0) - { - parent = ((xcb_screen_t *)_ecore_xcb_screen)->root; - screen = ((xcb_screen_t *)_ecore_xcb_screen); - } - else - { - xcb_screen_iterator_t iter_screen; - xcb_get_geometry_reply_t *rep; - Ecore_X_Drawable draw; - Ecore_X_Window root; + return window; +} - draw = parent; - rep = xcb_get_geometry_reply(_ecore_xcb_conn, - xcb_get_geometry_unchecked(_ecore_xcb_conn, - draw), - NULL); - if (!rep) - return win; +/** + * 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; - root = rep->root; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - free(rep); + 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; - for (; iter_screen.rem; xcb_screen_next(&iter_screen)) - { - if (iter_screen.data->root == root) - { - screen = iter_screen.data; - } - } - } - if (!screen) - return win; - - /* we get the X visual types */ - iter_depth = xcb_screen_allowed_depths_iterator(screen); - for (; iter_depth.rem; xcb_depth_next(&iter_depth)) { - if (iter_depth.data->depth == 32) { - iter_visualtype = xcb_depth_visuals_iterator(iter_depth.data); - break; - } - } - - /* we get the X render visual id */ - rep_pict_format = xcb_render_query_pict_formats_reply(_ecore_xcb_conn, - cookie_pict_format, - NULL); - if (!rep_pict_format) - return win; - - for (; iter_visualtype.rem; xcb_visualtype_next(&iter_visualtype)) { - if (iter_visualtype.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) { - xcb_render_pictforminfo_iterator_t iter_forminfo; - xcb_render_pictscreen_iterator_t iter_pictscreen; - xcb_render_pictformat_t pict_format = { 0 }; - - iter_forminfo = xcb_render_query_pict_formats_formats_iterator(rep_pict_format); - for (; iter_forminfo.rem; xcb_render_pictforminfo_next(&iter_forminfo)) { - if (iter_forminfo.data->type == XCB_RENDER_PICT_TYPE_DIRECT && - iter_forminfo.data->direct.alpha_mask && iter_forminfo.data->depth == 32) { - pict_format = iter_forminfo.data->id; - break; - } - } - if (pict_format == 0) { - free(rep_pict_format); - return win; - } - iter_pictscreen = xcb_render_query_pict_formats_screens_iterator(rep_pict_format); - for (; iter_pictscreen.rem; xcb_render_pictscreen_next(&iter_pictscreen)) { - xcb_render_pictdepth_iterator_t iter_depth; - - iter_depth = xcb_render_pictscreen_depths_iterator(iter_pictscreen.data); - for (; iter_depth.rem; xcb_render_pictdepth_next(&iter_depth)) { - xcb_render_pictvisual_iterator_t iter_visual; - - iter_visual = xcb_render_pictdepth_visuals_iterator(iter_depth.data); - for (; iter_visual.rem; xcb_render_pictvisual_next(&iter_visual)) { - if ((iter_visual.data->visual == iter_visualtype.data->visual_id) && - (pict_format == iter_visual.data->format)) { - vis = iter_visual.data->visual; - break; - } - } - } - } - } - } + 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; +} - free(rep_pict_format); +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; - if (vis == 0) - return win; + 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_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; + 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, /* depth */ - win, parent, - x, y, w, h, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, - vis, - value_mask, + 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; } -#endif /* ECORE_XCB_RENDER */ +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; -/* FIXME: round trip */ -EAPI int -ecore_x_window_argb_get(Ecore_X_Window win) -{ - uint8_t ret = 0; -#ifdef ECORE_XCB_RENDER - xcb_render_pictforminfo_iterator_t iter_forminfo; - xcb_render_pictscreen_iterator_t iter_pictscreen; - xcb_render_pictformat_t pict_format = { 0 }; - xcb_render_query_pict_formats_reply_t *rep_pictformat; - xcb_get_window_attributes_reply_t *rep; - xcb_visualid_t visual; - - rep = xcb_get_window_attributes_reply(_ecore_xcb_conn, - xcb_get_window_attributes_unchecked(_ecore_xcb_conn, - win), - NULL); - if (!rep) - return ret; - - visual = rep->visual; - - free(rep); - - rep_pictformat = xcb_render_query_pict_formats_reply(_ecore_xcb_conn, - xcb_render_query_pict_formats_unchecked(_ecore_xcb_conn), - NULL); - if (!rep_pictformat) - return ret; - - iter_forminfo = xcb_render_query_pict_formats_formats_iterator(rep_pictformat); - for (; iter_forminfo.rem; xcb_render_pictforminfo_next(&iter_forminfo)) - { - if ((iter_forminfo.data->type == XCB_RENDER_PICT_TYPE_DIRECT) && - (iter_forminfo.data->direct.alpha_mask)) - { - pict_format = iter_forminfo.data->id; - break; - } - } - if (pict_format == 0) - { - free(rep_pictformat); + if (!ecore_x_window_visible_get(base)) return 0; - return ret; - } + 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); - iter_pictscreen = xcb_render_query_pict_formats_screens_iterator(rep_pictformat); - for (; iter_pictscreen.rem; xcb_render_pictscreen_next(&iter_pictscreen)) + for (i = (num - 1); i >= 0; --i) { - xcb_render_pictdepth_iterator_t iter_depth; + skipit = EINA_FALSE; - iter_depth = xcb_render_pictscreen_depths_iterator(iter_pictscreen.data); - for (; iter_depth.rem; xcb_render_pictdepth_next(&iter_depth)) + if (skip) { - xcb_render_pictvisual_iterator_t iter_visual; + int j = 0; - iter_visual = xcb_render_pictdepth_visuals_iterator(iter_depth.data); - for (; iter_visual.rem; xcb_render_pictvisual_next(&iter_visual)) + for (j = 0; j < skip_num; j++) { - if ((iter_visual.data->visual == visual) && - (pict_format == iter_visual.data->format)) + if (windows[i] == skip[j]) { - ret = 1; - break; + skipit = EINA_TRUE; + goto onward; } } } - } +onward: + if (!skipit) + { + Ecore_X_Window child = 0; - free(rep_pictformat); -#endif /* ECORE_XCB_RENDER */ + child = + _ecore_xcb_window_at_xy_get(windows[i], + wx, wy, x, y, skip, skip_num); + if (child) + { + if (reply) free(reply); + return child; + } + } + } - return ret; + 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; +} -/** - * Set if a window should be ignored. - * @param window The given window. - * @param ignore if to ignore - */ -EAPI void -ecore_x_window_ignore_set(Ecore_X_Window window, - int ignore) +void +_ecore_xcb_window_button_grab_remove(Ecore_X_Window win) { - int i, j; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (ignore) - { - if (ignore_list) - { - for (i = 0; i < ignore_num; i++) - { - if (window == ignore_list[i]) - return; - } - ignore_list = realloc(ignore_list, (ignore_num + 1) * sizeof(Ecore_X_Window)); - if (!ignore_list) return; - ignore_list[ignore_num++] = window; - } - else - { - ignore_num = 0; - ignore_list = malloc(sizeof(Ecore_X_Window)); - ignore_list[ignore_num++] = window; - } - } - else + if (_ecore_xcb_button_grabs_num > 0) { - if (!ignore_list) return; - for (i = 0, j = 0; i < ignore_num; i++) - { - if (window != ignore_list[i]) - ignore_list[i] = ignore_list[j++]; - else - ignore_num--; - } - ignore_list = realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window)); + 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; + } } } -/** - * 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) +void +_ecore_xcb_window_key_grab_remove(Ecore_X_Window win) { - if (num) *num = ignore_num; - return ignore_list; + 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; + } + } } -/** - * 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. - * - * To use this function, you must call before, and in order, - * ecore_x_drawable_geometry_get_prefetch(), which sends the GetGeometry request, - * then ecore_x_drawable_geometry_get_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Geometry_Group - */ -EAPI void -ecore_x_window_size_get(Ecore_X_Window window, - int *width, - int *height) +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) { - if (window == 0) - window = ((xcb_screen_t *)_ecore_xcb_screen)->root; + 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; - ecore_x_drawable_geometry_get(window, NULL, NULL, width, height); + 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; + } + } } -/** - * Retrieves the geometry of the given window. - * @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. - * - * To use this function, you must call before, and in order, - * ecore_x_drawable_geometry_get_prefetch(), which sends the GetGeometry request, - * then ecore_x_drawable_geometry_get_fetch(), which gets the reply. - * @ingroup Ecore_X_Window_Geometry_Group - */ -EAPI void -ecore_x_window_geometry_get(Ecore_X_Window window, - int *x, - int *y, - int *width, - int *height) +static int +_ecore_xcb_window_modifiers_get(unsigned int state) { - if (!window) - window = ((xcb_screen_t *)_ecore_xcb_screen)->root; - - ecore_x_drawable_geometry_get(window, x, y, width, height); + 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; } -/** - * 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) +static xcb_visualtype_t * +_ecore_xcb_window_find_visual_by_id(xcb_visualid_t id) { - /* doesn't make sense to call this on a root window */ - if (!win) - return 0; + xcb_depth_iterator_t diter; + xcb_visualtype_iterator_t viter; - return ecore_x_drawable_border_width_get(win); + 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; } -/** - * 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) +#ifdef ECORE_XCB_XPRINT +static xcb_screen_t * +_ecore_xcb_window_screen_of_display(int screen) { - return ecore_x_drawable_depth_get(win); + 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 index c7b81af..e00fdc1 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_window_prop.c @@ -1,871 +1,720 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" -#include "Ecore_X_Atoms.h" - +#include -/* - * Set CARD32 (array) property - */ -EAPI void -ecore_x_window_prop_card32_set(Ecore_X_Window win, +EAPI int +ecore_x_window_prop_card32_get(Ecore_X_Window win, Ecore_X_Atom atom, - unsigned int *val, - unsigned int num) -{ - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, - atom, ECORE_X_ATOM_CARDINAL, 32, num, (const void *)val); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param atom The atom. - */ -EAPI void -ecore_x_window_prop_card32_get_prefetch(Ecore_X_Window window, - 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; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window, - atom, - ECORE_X_ATOM_CARDINAL, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); -} + 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; -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_card32_get_prefetch(). - */ -EAPI void -ecore_x_window_prop_card32_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + 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; + } + } - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + if (reply) free(reply); + return num; } -/* - * 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 __UNUSED__, - Ecore_X_Atom atom __UNUSED__, - unsigned int *val, - unsigned int len) +EAPI void +ecore_x_window_prop_card32_set(Ecore_X_Window win, + Ecore_X_Atom atom, + unsigned int *val, + unsigned int num) { - xcb_get_property_reply_t *reply; - - reply = _ecore_xcb_reply_get(); - if (!reply || - (reply->type != ECORE_X_ATOM_CARDINAL) || - (reply->format != 32)) - return -1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (reply->value_len < len) - len = xcb_get_property_value_length(reply); +#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; - if (val) - memcpy(val, xcb_get_property_value(reply), len); + v2 = malloc(num * sizeof(long)); + if (!v2) return; + for (i = 0; i < num; i++) + v2[i] = val[i]; - return (int)len; + 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 } -/* - * 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 __UNUSED__, - Ecore_X_Atom atom __UNUSED__, - unsigned int **plist) +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; + int num = -1; - if (plist) - *plist = NULL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply = _ecore_xcb_reply_get(); - if (!reply) - return -1; + if (list) *list = NULL; - if ((reply->type == XCB_NONE) || - (reply->value_len == 0)) - num = 0; - else if ((reply->type == ECORE_X_ATOM_CARDINAL) && - (reply->format == 32)) + 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 { - uint32_t *val; - - num = xcb_get_property_value_length(reply); - if (plist) - { - val = (uint32_t *)malloc (num); - if (!val) - goto error; - - memcpy(val, xcb_get_property_value(reply), num); - *plist = val; - } + 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; + } } - error: - + free(reply); 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 *xids, - unsigned int num) -{ - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, - atom, type, 32, num, xids); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param atom The atom. - * @param type The atom type. - */ -EAPI void -ecore_x_window_prop_xid_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom, - Ecore_X_Atom type) +EAPI int +ecore_x_window_prop_atom_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *list, + unsigned int len) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window, - atom, - type, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_ATOM, list, len); } - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_xid_get_prefetch(). - */ EAPI void -ecore_x_window_prop_xid_get_fetch(void) +ecore_x_window_prop_atom_set(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom *list, + unsigned int num) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + /* 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); } -/* - * 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 __UNUSED__, - Ecore_X_Atom atom __UNUSED__, - Ecore_X_Atom type __UNUSED__, +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 len) + unsigned int num) { - xcb_get_property_reply_t *reply; - int num = len; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return -1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - if (reply->type == XCB_NONE) - num = 0; - else if (reply->format == 32) - { - if (reply->value_len < len) - num = xcb_get_property_value_length(reply); +#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; - if (xids) - memcpy(xids, xcb_get_property_value(reply), num); - } + v2 = malloc(num * sizeof(long)); + if (!v2) return; + for (i = 0; i < num; i++) + v2[i] = xids[i]; - return num; + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, atom, + type, 32, num, (unsigned char *)v2); + free(v2); +// ecore_x_flush(); +#endif } -/* - * 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 __UNUSED__, - Ecore_X_Atom atom __UNUSED__, - Ecore_X_Atom type __UNUSED__, - Ecore_X_ID **pxids) +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 = -1; + int num = 0; - if (pxids) - *pxids = NULL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - reply = _ecore_xcb_reply_get(); - if (!reply) - return -1; + 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 == XCB_NONE) || - (reply->value_len == 0)) - num = 0; - else if ((reply->type == ECORE_X_ATOM_CARDINAL) && - (reply->format == 32)) + if ((reply->type != type) || (reply->format != 32)) + num = -1; + else if (reply->value_len == 0) + num = 0; + else { - uint32_t *val; - - num = xcb_get_property_value_length(reply); - if (pxids) - { - val = (uint32_t *)malloc (num); - if (!val) - return -1; - - memcpy(val, xcb_get_property_value(reply), num); - *pxids = val; - } - } - - return num; -} + unsigned int i = 0; + unsigned char *v; -/* - * 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; - int num; + if (reply->value_len < len) + len = reply->value_len; - num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst); - if (num < 0) - return; /* Error - assuming invalid window */ + v = xcb_get_property_value(reply); + for (i = 0; i < len; i++) + xids[i] = ((uint32_t *)v)[i]; - /* Is it there? */ - for (i = 0; i < num; i++) - { - if (lst[i] == item) - break; + num = len; } - 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 *list, - unsigned int num) -{ - ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_ATOM, list, num); + if (reply) free(reply); + return num; } -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param atom Property atom. - */ EAPI void -ecore_x_window_prop_atom_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom) +ecore_x_window_prop_string_set(Ecore_X_Window win, + Ecore_X_Atom type, + const char *str) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window, - atom, - ECORE_X_ATOM_ATOM, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, type, + ECORE_X_ATOM_UTF8_STRING, 8, strlen(str), str); +// ecore_x_flush(); } - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_atom_get_prefetch(). - */ -EAPI void -ecore_x_window_prop_atom_get_fetch(void) +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; - cookie.sequence = _ecore_xcb_cookie_get(); + 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); - _ecore_xcb_reply_cache(reply); -} + if (!reply) return NULL; -/* - * 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 *list, - unsigned int len) -{ - return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_ATOM, list, len); -} + 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'; -/* - * 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 **plist) -{ - return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_ATOM, plist); -} + 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); + } -/* - * 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) -{ - ecore_x_window_prop_xid_list_change(win, atom, ECORE_X_ATOM_ATOM, item, op); + free(reply); + return str; } -/* - * Set Window (array) property - */ -EAPI void -ecore_x_window_prop_window_set(Ecore_X_Window win, +EAPI int +ecore_x_window_prop_window_get(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *list, - unsigned int num) -{ - ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_WINDOW, list, num); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param atom The atom. - */ -EAPI void -ecore_x_window_prop_window_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom atom) + unsigned int len) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window, - atom, - ECORE_X_ATOM_WINDOW, - 0, 0x7fffffff); - _ecore_xcb_cookie_cache(cookie.sequence); + return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_WINDOW, list, len); } - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_window_get_prefetch(). - */ EAPI void -ecore_x_window_prop_window_get_fetch(void) -{ - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} - -/* - * 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_window_prop_window_set(Ecore_X_Window win, Ecore_X_Atom atom, Ecore_X_Window *list, - unsigned int len) + unsigned int num) { - return ecore_x_window_prop_xid_get(win, atom, ECORE_X_ATOM_WINDOW, list, len); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + ecore_x_window_prop_xid_set(win, atom, ECORE_X_ATOM_WINDOW, list, num); } -/* - * 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 **plist) + Ecore_X_Window **plst) { - return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_WINDOW, plist); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_WINDOW, plst); } -/** - * To be documented. - * - * FIXME: To be fixed. - */ EAPI Ecore_X_Atom ecore_x_window_prop_any_type(void) { - return XCB_GET_PROPERTY_TYPE_ANY; + return XCB_ATOM_ANY; } -/** - * To be documented. - * @param window The window. - * @param property The property atom. - * @param type The type atom. - * @param size The size. - * @param data The data. - * @param number The size of the data. - * - * FIXME: To be fixed. - */ EAPI void -ecore_x_window_prop_property_set(Ecore_X_Window window, - Ecore_X_Atom property, - Ecore_X_Atom type, - int size, - void *data, - int number) -{ - if (window == 0) window = ((xcb_screen_t *)_ecore_xcb_screen)->root; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, window, - property, type, - size, number, data); -} - -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param property Property atom. - * @param type Type atom. - */ -EAPI void -ecore_x_window_prop_property_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom property, - Ecore_X_Atom type) +ecore_x_window_prop_property_del(Ecore_X_Window win, + Ecore_X_Atom property) { - xcb_get_property_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - property, type, 0, LONG_MAX); - _ecore_xcb_cookie_cache(cookie.sequence); + xcb_delete_property(_ecore_xcb_conn, win, property); } - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_property_get_prefetch(). - */ EAPI void -ecore_x_window_prop_property_get_fetch(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) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + 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(); + } + } } -/** - * To be documented. - * @param window The window (Unused). - * @param property The property atom (Unused). - * @param type The type atom (Unused). - * @param size The size (Unused). - * @param data The returned data. - * @param num The size of the data. - * @return 1 on success, 0 otherwise. - * - * FIXME: To be fixed. - */ EAPI int -ecore_x_window_prop_property_get(Ecore_X_Window window __UNUSED__, - Ecore_X_Atom property __UNUSED__, - Ecore_X_Atom type __UNUSED__, - int size __UNUSED__, +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; - /* make sure these are initialized */ - if (num) *num = 0L; + if (num) *num = 0; if (data) *data = NULL; - else /* we can't store the retrieved data, so just return */ - return 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) + else return 0; - if ((reply->format != size) || - (reply->value_len == 0)) - return 0; - - *data = malloc(reply->value_len); - if (!*data) - return 0; + if (win == 0) + win = ((xcb_screen_t *)_ecore_xcb_screen)->root; - memcpy(*data, xcb_get_property_value(reply), - xcb_get_property_value_length(reply)); + 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 (num) - *num = reply->value_len; + if (!(*data = malloc(reply->value_len * reply->format / 8))) + { + free(reply); + return 0; + } - return reply->format; -} + 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; + } -EAPI void -ecore_x_window_prop_property_del(Ecore_X_Window window, - Ecore_X_Atom property) -{ - xcb_delete_property(_ecore_xcb_conn, window, property); + if (num) *num = reply->value_len; + format = reply->format; + free(reply); + return format; } -/** - * Sends the ListProperties request. - * @param window Window whose properties are requested. - */ -EAPI void -ecore_x_window_prop_list_prefetch(Ecore_X_Window window) +EAPI int +ecore_x_window_prop_atom_list_get(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom **list) { - xcb_list_properties_cookie_t cookie; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - cookie = xcb_list_properties_unchecked(_ecore_xcb_conn, window); - _ecore_xcb_cookie_cache(cookie.sequence); + return ecore_x_window_prop_xid_list_get(win, atom, ECORE_X_ATOM_ATOM, list); } - -/** - * Gets the reply of the ListProperties request sent by ecore_x_window_prop_list_prefetch(). - */ EAPI void -ecore_x_window_prop_list_fetch(void) +ecore_x_window_prop_atom_list_change(Ecore_X_Window win, + Ecore_X_Atom atom, + Ecore_X_Atom item, + int op) { - xcb_list_properties_cookie_t cookie; - xcb_list_properties_reply_t *reply; - - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_list_properties_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_xid_list_change(win, atom, ECORE_X_ATOM_ATOM, item, op); } - -/** - * To be documented. - * @param window The window (Unused). - * @param num_ret The number of atoms. - * @return The returned atoms. - * - * FIXME: To be fixed. - */ -EAPI Ecore_X_Atom * -ecore_x_window_prop_list(Ecore_X_Window window __UNUSED__, - int *num_ret) +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_list_properties_reply_t *reply; - Ecore_X_Atom *atoms; - - if (num_ret) *num_ret = 0; - - reply = _ecore_xcb_reply_get(); - if (!reply) - return NULL; + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + int num = -1; - atoms = (Ecore_X_Atom *)malloc(reply->atoms_len * sizeof(Ecore_X_Atom)); - if (!atoms) - return NULL; - memcpy(atoms, - xcb_list_properties_atoms(reply), - reply->atoms_len * sizeof(Ecore_X_Atom)); - if(num_ret) - *num_ret = reply->atoms_len; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return atoms; -} + if (xids) *xids = NULL; -/** - * 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) -{ - if (win == 0) win = ((xcb_screen_t *)_ecore_xcb_screen)->root; - xcb_change_property(_ecore_xcb_conn, XCB_PROP_MODE_REPLACE, win, - type, ECORE_X_ATOM_UTF8_STRING, - 8, strlen(str), str); -} + 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; -/** - * Sends the GetProperty request. - * @param window Window whose properties are requested. - * @param type The atom. - */ -EAPI void -ecore_x_window_prop_string_get_prefetch(Ecore_X_Window window, - Ecore_X_Atom type) -{ - xcb_get_property_cookie_t cookie; + 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; + } + } - cookie = xcb_get_property_unchecked(_ecore_xcb_conn, 0, - window ? window : ((xcb_screen_t *)_ecore_xcb_screen)->root, - type, XCB_GET_PROPERTY_TYPE_ANY, 0L, 1000000L); - _ecore_xcb_cookie_cache(cookie.sequence); + free(reply); + return num; } - -/** - * Gets the reply of the GetProperty request sent by ecore_x_window_prop_string_get_prefetch(). - */ EAPI void -ecore_x_window_prop_string_get_fetch(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) { - xcb_get_property_cookie_t cookie; - xcb_get_property_reply_t *reply; + Ecore_X_ID *lst; + int i = 0, num = 0; - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_get_property_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; -/** - * Get a window string property. - * @param window The window - * @param type The property - * - * Return window string property of a window. String must be free'd when done. - * - * To use this function, you must call before, and in order, - * ecore_x_window_prop_string_get_prefetch(), which sends the GetProperty request, - * then ecore_x_window_prop_string_get_fetch(), which gets the reply. - */ -EAPI char * -ecore_x_window_prop_string_get(Ecore_X_Window window __UNUSED__, - Ecore_X_Atom type __UNUSED__) -{ - xcb_get_property_reply_t *reply; - char *str = NULL; + num = ecore_x_window_prop_xid_list_get(win, atom, type, &lst); + if (num < 0) return; - reply = _ecore_xcb_reply_get(); - if (!reply) - return NULL; + for (i = 0; i < num; i++) + { + if (lst[i] == item) break; + } - if (reply->type == ECORE_X_ATOM_UTF8_STRING) + if (i < num) { - int length; - - length = reply->value_len; - str = (char *)malloc(length + 1); - memcpy(str, - xcb_get_property_value(reply), - length); - str[length] = '\0'; + if (op == ECORE_X_PROP_LIST_ADD) + goto done; + num--; + for (; i < num; i++) + lst[i] = lst[i + 1]; } else { - /* FIXME: to be done... */ - -/* #ifdef X_HAVE_UTF8_STRING */ -/* s = Xutf8TextPropertyToTextList(_ecore_xcb_conn, &xtp, */ -/* &list, &items); */ -/* #else */ -/* s = XmbTextPropertyToTextList(_ecore_xcb_conn, &xtp, */ -/* &list, &items); */ -/* #endif */ -/* 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); */ + 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); - return str; +done: + if (lst) free(lst); } -/* FIXME : round trips because of GetWMProtocols */ -/* should we rewrite its code ? */ -EAPI int -ecore_x_window_prop_protocol_isset(Ecore_X_Window window, +EAPI Eina_Bool +ecore_x_window_prop_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol) { - Ecore_X_Atom *protos; - Ecore_X_Atom proto; - uint32_t protos_count; - uint32_t i; - uint8_t ret = 0; - - /* check for invalid values */ - if (protocol >= ECORE_X_WM_PROTOCOL_NUM) - return ret; - - proto = _ecore_xcb_atoms_wm_protocols[protocol]; - - if (!xcb_get_wm_protocols(_ecore_xcb_conn, window, &protos_count, &protos)) - return ret; - - for (i = 0; i < protos_count; i++) - if (protos[i] == proto) - { - ret = 1; - break; - } - - free(protos); + 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; } -/** - * To be documented. - * @param window The window. - * @param num_ret The number of WM protocols. - * @return The returned WM protocols. - * - * FIXME: To be fixed. - */ - -/* FIXME : round trips because of get_wm_protocols */ -/* should we rewrite its code ? */ - EAPI Ecore_X_WM_Protocol * -ecore_x_window_prop_protocol_list_get(Ecore_X_Window window, +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; - Ecore_X_Atom *protos; - uint32_t protos_count; - uint32_t i; - if (!xcb_get_wm_protocols(_ecore_xcb_conn, window, &protos_count, &protos)) - return NULL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + + if (!num_ret) return NULL; + + *num_ret = 0; - if ((!protos) || (protos_count <= 0)) return NULL; +#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; - prot_ret = calloc(1, protos_count * sizeof(Ecore_X_WM_Protocol)); + 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) { - free(protos); - return NULL; +#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 < protos_count; i++) + + 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_protocols[j] == protos[i]) - prot_ret[i] = j; - } + 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; + } } - free(protos); - *num_ret = protos_count; + 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 index c025673..82326fa 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_window_shadow.c @@ -1,76 +1,60 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - -/* #include "Ecore.h" */ #include "ecore_xcb_private.h" -#include "Ecore_X.h" - typedef struct _Shadow Shadow; struct _Shadow { - Shadow *parent; - Shadow **children; - Ecore_X_Window win; - int children_num; - short x, y; - unsigned short w, h; + Shadow *parent, **children; + Ecore_X_Window win; + int children_num; + short x, y; + unsigned short w, h; }; -static int shadow_count = 0; +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; - Shadow **sl; + 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_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; - int j; + xcb_get_geometry_cookie_t cookie_geom; + xcb_query_tree_cookie_t cookie_tree; + int i, j; - cookie_attr = xcb_get_window_attributes_unchecked(_ecore_xcb_conn, window); - cookie_geom = xcb_get_geometry_unchecked(_ecore_xcb_conn, window); - cookie_tree = xcb_query_tree_unchecked(_ecore_xcb_conn, window); + 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) - { - reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL); - if (reply_geom) free(reply_geom); - reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); - if (reply_tree) free(reply_tree); - return NULL; - } - + if (!reply_attr) return NULL; if (reply_attr->map_state != XCB_MAP_STATE_VIEWABLE) { - reply_geom = xcb_get_geometry_reply(_ecore_xcb_conn, cookie_geom, NULL); - if (reply_geom) free(reply_geom); - reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); - if (reply_tree) free(reply_tree); + free(reply_attr); return NULL; } free(reply_attr); - s = calloc(1, sizeof(Shadow)); - if (!s) return NULL; - + 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) + if (!reply_geom) return NULL; + + if (!(s = calloc(1, sizeof(Shadow)))) { - reply_tree = xcb_query_tree_reply(_ecore_xcb_conn, cookie_tree, NULL); - if (reply_tree) free(reply_tree); + free(reply_geom); return NULL; } @@ -82,82 +66,86 @@ _ecore_x_window_tree_walk(Ecore_X_Window window) 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) -/* if (XQueryTree(_ecore_xcb_conn, s->win, &root_win, &parent_win, */ -/* &list, &num)) */ { xcb_window_t *list; - int num; + 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; - } - } + 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; + 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); + 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; + 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]); + if (!shadow_base[i]) continue; + _ecore_x_window_tree_shadow_free1(shadow_base[i]); } free(shadow_base); shadow_base = NULL; @@ -167,55 +155,62 @@ _ecore_x_window_tree_shadow_free(void) static void _ecore_x_window_tree_shadow_populate(void) { - Ecore_X_Window *roots; - int i, num; + Ecore_X_Window *roots = NULL; + int i = 0, num = 0; - roots = ecore_x_window_root_list(&num); - if (roots) + 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); + 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) -{ +/* + 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) -{ + 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) +_ecore_x_window_shadow_tree_find_shadow(Shadow *s, + Ecore_X_Window win) { Shadow *ss; - int i; + 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; - } + 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; } @@ -223,77 +218,127 @@ Shadow * _ecore_x_window_shadow_tree_find(Ecore_X_Window base) { Shadow *s; - int i; + 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; + 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_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; - int i, j; - int wx, wy; + 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; - } - } - } + 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) +_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; + _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 @@ -303,11 +348,17 @@ _ecore_x_window_shadow_tree_at_xy_get(Ecore_X_Window base, int bx, int by, int x * @param base The base window to start searching from (normally root). * @param x The given X position. * @param y The given Y position. - * @return The window at that 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) +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); } @@ -321,25 +372,28 @@ ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y * @ingroup Ecore_X_Window_Geometry_Group */ EAPI Ecore_X_Window -ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win) +ecore_x_window_shadow_parent_get(Ecore_X_Window root __UNUSED__, + Ecore_X_Window win) { Shadow *s; - int i; + int i = 0; if (!shadow_base) { - _ecore_x_window_tree_shadow_populate(); - if (!shadow_base) return 0; + _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; - } + 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; } @@ -353,3 +407,4 @@ 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..58444cd --- /dev/null +++ b/src/lib/ecore_x/xcb/ecore_xcb_xfixes.c @@ -0,0 +1,744 @@ +#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. + * + * @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 index 52aaf96..37a2339 100644 --- a/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c +++ b/src/lib/ecore_x/xcb/ecore_xcb_xinerama.c @@ -1,197 +1,139 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ - #include "ecore_xcb_private.h" - - -/** - * @defgroup Ecore_X_Xinerama_Group X Xinerama Extension Functions - * - * Functions related to the X Xinerama extension. - */ - - #ifdef ECORE_XCB_XINERAMA -static int _xinerama_available = 0; -static xcb_xinerama_query_version_cookie_t _ecore_xcb_xinerama_init_cookie; -#endif /* ECORE_XCB_XINERAMA */ - +# include +#endif -/* To avoid round trips, the initialization is separated in 2 - functions: _ecore_xcb_xinerama_init and - _ecore_xcb_xinerama_init_finalize. The first one gets the cookies and - the second one gets the replies. */ +/* local variables */ +static Eina_Bool _xinerama_avail = EINA_FALSE; +static Eina_Bool _xinerama_active = EINA_FALSE; void -_ecore_x_xinerama_init(const xcb_query_extension_reply_t *reply) +_ecore_xcb_xinerama_init(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); + #ifdef ECORE_XCB_XINERAMA - if (reply && (reply->present)) - _ecore_xcb_xinerama_init_cookie = xcb_xinerama_query_version_unchecked(_ecore_xcb_conn, 1, 2); -#endif /* ECORE_XCB_XINERAMA */ + xcb_prefetch_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); +#endif } void -_ecore_x_xinerama_init_finalize(void) +_ecore_xcb_xinerama_finalize(void) { #ifdef ECORE_XCB_XINERAMA - xcb_xinerama_query_version_reply_t *reply; + const xcb_query_extension_reply_t *ext_reply; +#endif - reply = xcb_xinerama_query_version_reply(_ecore_xcb_conn, - _ecore_xcb_xinerama_init_cookie, NULL); + LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (reply) +#ifdef ECORE_XCB_XINERAMA + ext_reply = xcb_get_extension_data(_ecore_xcb_conn, &xcb_xinerama_id); + if ((ext_reply) && (ext_reply->present)) { - if ((reply->major >= 1) && - (reply->minor >= 1)) - _xinerama_available = 1; - free(reply); + 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 /* ECORE_XCB_XINERAMA */ +#endif } - -/** - * Return whether the X server supports the Xinerama Extension. - * @return 1 if the X Xinerama Extension is available, 0 otherwise. - * - * Return 1 if the X server supports the Fixes Xinerama version 1.1, - * 0 otherwise. - * @ingroup Ecore_X_Xinerama_Group - */ EAPI int -ecore_x_xinerama_query(void) -{ -#ifdef ECORE_XCB_XINERAMA - return _xinerama_available; -#else - return 0; -#endif /* ECORE_XCB_XINERAMA */ -} - - -/** - * Sends the XineramaQueryScreens request. - * @ingroup Ecore_X_Xinerama_Group - */ -EAPI void -ecore_x_xinerama_query_screens_prefetch(void) -{ -#ifdef ECORE_XCB_XINERAMA - xcb_xinerama_query_screens_cookie_t cookie; - - cookie = xcb_xinerama_query_screens_unchecked(_ecore_xcb_conn); - _ecore_xcb_cookie_cache(cookie.sequence); -#endif /* ECORE_XCB_XINERAMA */ -} - - -/** - * Gets the reply of the XineramaQueryScreens request sent by ecore_x_xinerama_query_screens_prefetch(). - * @ingroup Ecore_X_Xinerama_Group - */ -EAPI void -ecore_x_xinerama_query_screens_fetch(void) +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 - cookie.sequence = _ecore_xcb_cookie_get(); - reply = xcb_xinerama_query_screens_reply(_ecore_xcb_conn, cookie, NULL); - _ecore_xcb_reply_cache(reply); -#endif /* ECORE_XCB_XINERAMA */ -} + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; + if (!_xinerama_avail) return 0; -/** - * Return the number of screens. - * @return The screen count. - * - * Return the number of screens. - * - * To use this function, you must call before, and in order, - * ecore_x_xinerama_query_screens_prefetch(), which sends the XineramaQueryScreens request, - * then ecore_x_xinerama_query_screens_fetch(), which gets the reply. - * @ingroup Ecore_X_Xinerama_Group - */ -EAPI int -ecore_x_xinerama_screen_count_get(void) -{ - int screen_count = 0; #ifdef ECORE_XCB_XINERAMA - xcb_xinerama_screen_info_iterator_t iter; - xcb_xinerama_query_screens_reply_t *reply; - - reply = _ecore_xcb_reply_get(); + 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 - iter = xcb_xinerama_query_screens_screen_info_iterator(reply); - screen_count = iter.rem; -#endif /* ECORE_XCB_XINERAMA */ - - return screen_count; + return count; } - -/** - * Get the geometry of the screen. - * @param screen The screen (Unused). - * @param x The X coordinate of the screen. - * @param y The Y coordinate of the screen - * @param width The width of the screen - * @param height The height of the screen - * @return 1 on success, 0 otherwise. - * - * Get the geometry of the screen whose number is @p screen. The - * returned values are stored in @p x, @p y, @p width and @p height. - * - * To use this function, you must call before, and in order, - * ecore_x_xinerama_query_screens_prefetch(), which sends the XineramaQueryScreens request, - * then ecore_x_xinerama_query_screens_fetch(), which gets the reply. - * @ingroup Ecore_X_Xinerama_Group - */ -EAPI int +EAPI Eina_Bool ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, - int *width, - int *height) + int *w, + int *h) { #ifdef ECORE_XCB_XINERAMA - xcb_xinerama_screen_info_iterator_t iter; + xcb_xinerama_query_screens_cookie_t cookie; xcb_xinerama_query_screens_reply_t *reply; + xcb_xinerama_screen_info_t *info; +#endif - reply = _ecore_xcb_reply_get(); - if (!reply) - { - if (x) *x = 0; - if (y) *y = 0; - if (width) *width = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels; - if (height) *height = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + CHECK_XCB_CONN; - return 0; - } + 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; - iter = xcb_xinerama_query_screens_screen_info_iterator(reply); - for (; iter.rem; screen--, xcb_xinerama_screen_info_next(&iter)) + 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) { - if (screen == 0) - { - if (x) *x = iter.data->x_org; - if (y) *y = iter.data->y_org; - if (width) *width = iter.data->width; - if (height) *height = iter.data->height; - return 1; - } + free(reply); + return EINA_FALSE; } -#endif /* ECORE_XCB_XINERAMA */ - if (x) *x = 0; - if (y) *y = 0; - if (width) *width = ((xcb_screen_t *)_ecore_xcb_screen)->width_in_pixels; - if (height) *height = ((xcb_screen_t *)_ecore_xcb_screen)->height_in_pixels; + 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 0; + 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 index 4cb9f8b..3c7364c 100644 --- a/src/lib/ecore_x/xlib/Makefile.am +++ b/src/lib/ecore_x/xlib/Makefile.am @@ -5,10 +5,13 @@ 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@ \ @@ -17,19 +20,25 @@ AM_CPPFLAGS = \ @XTEST_CFLAGS@ \ @x_cflags@ \ -I$(top_srcdir)/src/lib/ecore \ --I$(top_srcdir)/src/lib/ecore_txt \ -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_txt \ --I$(top_builddir)/src/lib/ecore_x +-I$(top_builddir)/src/lib/ecore_x \ +-I$(top_builddir)/src/lib/ecore_input \ +@EVAS_CFLAGS@ \ +@EINA_CFLAGS@ -noinst_LTLIBRARIES = libecore_x_xlib.la +noinst_LTLIBRARIES = libecore_x_xlib.la -libecore_x_xlib_la_SOURCES = \ +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 \ @@ -51,14 +60,23 @@ ecore_x_dpms.c \ ecore_x_drawable.c \ ecore_x_cursor.c \ ecore_x_test.c \ -ecore_x_atoms.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@ \ @@ -67,13 +85,9 @@ libecore_x_xlib_la_LIBADD = \ @XTEST_LIBS@ \ @x_libs@ \ $(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_txt/libecore_txt.la - -libecore_x_xlib_la_LDFLAGS = -version-info @version_info@ - -libecore_x_xlib_la_DEPENDENCIES = \ -$(top_builddir)/src/lib/ecore/libecore.la \ -$(top_builddir)/src/lib/ecore_txt/libecore_txt.la +$(top_builddir)/src/lib/ecore_input/libecore_input.la \ +@EINA_LIBS@ \ +@dlopen_libs@ endif diff --git a/src/lib/ecore_x/xlib/ecore_x.c b/src/lib/ecore_x/xlib/ecore_x.c index 9be563f..7cb777d 100644 --- a/src/lib/ecore_x/xlib/ecore_x.c +++ b/src/lib/ecore_x/xlib/ecore_x.c @@ -1,29 +1,58 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -#include "ecore_private.h" +#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 int _ecore_x_fd_handler(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_x_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler); -static int _ecore_x_key_mask_get(KeySym sym); +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 +#endif /* ifdef ECORE_XRANDR */ #ifdef ECORE_XFIXES static int _ecore_x_event_fixes_selection_id = 0; -#endif +#endif /* ifdef ECORE_XFIXES */ #ifdef ECORE_XDAMAGE static int _ecore_x_event_damage_id = 0; -#endif +#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; @@ -31,25 +60,20 @@ 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; -int _ecore_x_xcursor = 0; +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_KEY_DOWN = 0; -EAPI int ECORE_X_EVENT_KEY_UP = 0; -EAPI int ECORE_X_EVENT_MOUSE_BUTTON_DOWN = 0; -EAPI int ECORE_X_EVENT_MOUSE_BUTTON_UP = 0; -EAPI int ECORE_X_EVENT_MOUSE_MOVE = 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_MOUSE_WHEEL = 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; @@ -70,29 +94,29 @@ 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_PROP_TITLE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE = 0; -EAPI int ECORE_X_EVENT_WINDOW_PROP_DESKTOP_CHANGE = 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; @@ -103,14 +127,146 @@ 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; + +EAPI int ECORE_X_RAW_BUTTON_PRESS = 0; +EAPI int ECORE_X_RAW_BUTTON_RELEASE = 0; +EAPI int ECORE_X_RAW_MOTION = 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 @@ -135,248 +291,346 @@ ecore_x_init(const char *name) #ifdef ECORE_XSS int screensaver_base = 0; int screensaver_err_base = 0; -#endif +#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 +#endif /* ifdef ECORE_XRANDR */ #ifdef ECORE_XFIXES int fixes_base = 0; int fixes_err_base = 0; -#endif +#endif /* ifdef ECORE_XFIXES */ #ifdef ECORE_XDAMAGE int damage_base = 0; int damage_err_base = 0; -#endif - - if (_ecore_x_init_count > 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) { - _ecore_x_init_count++; - return _ecore_x_init_count; + 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) return 0; + 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 + ShapeNotify; - if (_ecore_x_event_shape_id >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_shape_id + 1; - + _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 + ScreenSaverNotify; -#endif - if (_ecore_x_event_screensaver_id >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_screensaver_id + 1; - + 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; + 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_sync_id = sync_base; + if (!XSyncInitialize(_ecore_x_disp, &major, &minor)) + _ecore_x_event_sync_id = 0; } - if (_ecore_x_event_sync_id + XSyncAlarmNotify >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_sync_id + XSyncAlarmNotify + 1; - + + 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 + RRScreenChangeNotify; - if (_ecore_x_event_randr_id >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_randr_id + 1; -#endif + _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 + XFixesSelectionNotify; - if (_ecore_x_event_fixes_selection_id >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_fixes_selection_id + 1; -#endif + _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 + XDamageNotify; - if (_ecore_x_event_damage_id >= _ecore_x_event_handlers_num) - _ecore_x_event_handlers_num = _ecore_x_event_damage_id + 1; -#endif + _ecore_x_event_damage_id = damage_base; - _ecore_x_event_handlers = calloc(_ecore_x_event_handlers_num, sizeof(void *)); - if (!_ecore_x_event_handlers) + 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 { - XCloseDisplay(_ecore_x_disp); - _ecore_x_fd_handler_handle = NULL; - _ecore_x_disp = NULL; - return 0; + 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); } -#ifdef ECORE_XCURSOR - _ecore_x_xcursor = XcursorSupportsARGB(_ecore_x_disp); + ECORE_X_EVENT_HANDLERS_GROW(xkb_base, XkbNumberEvents); #endif - _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; + + _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; + _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; + _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; + _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] = _ecore_x_event_handle_randr_change; -#endif + { + _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 + _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 + _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_KEY_DOWN) + if (!ECORE_X_EVENT_ANY) { - ECORE_X_EVENT_KEY_DOWN = ecore_event_type_new(); - ECORE_X_EVENT_KEY_UP = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_BUTTON_DOWN = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_BUTTON_UP = ecore_event_type_new(); - ECORE_X_EVENT_MOUSE_MOVE = 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_MOUSE_WHEEL = 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_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_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_DAMAGE_NOTIFY = ecore_event_type_new(); + 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_WINDOW_DELETE_REQUEST = ecore_event_type_new(); - /* - ECORE_X_EVENT_WINDOW_PROP_TITLE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE = ecore_event_type_new(); - ECORE_X_EVENT_WINDOW_PROP_DESKTOP_CHANGE = 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_GENERIC = ecore_event_type_new(); + + ECORE_X_RAW_BUTTON_PRESS = ecore_event_type_new(); + ECORE_X_RAW_BUTTON_RELEASE = ecore_event_type_new(); + ECORE_X_RAW_MOTION = ecore_event_type_new(); } - - /* 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_Mode_switch); - if (!ECORE_X_MODIFIER_WIN) - ECORE_X_MODIFIER_WIN = _ecore_x_key_mask_get(XK_Meta_L); - - 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_fd_handler_handle = + + _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); + ECORE_FD_READ, + _ecore_x_fd_handler, _ecore_x_disp, + _ecore_x_fd_handler_buf, _ecore_x_disp); if (!_ecore_x_fd_handler_handle) - { - XCloseDisplay(_ecore_x_disp); - free(_ecore_x_event_handlers); - _ecore_x_fd_handler_handle = NULL; - _ecore_x_disp = NULL; - _ecore_x_event_handlers = NULL; - return 0; - } + goto free_event_handlers; _ecore_x_atoms_init(); @@ -388,13 +642,17 @@ ecore_x_init(const char *name) /* 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_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(); @@ -402,33 +660,73 @@ ecore_x_init(const char *name) _ecore_x_damage_init(); _ecore_x_composite_init(); _ecore_x_dpms_init(); - - _ecore_x_init_count++; - + _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) { - _ecore_x_init_count--; - if (_ecore_x_init_count > 0) return _ecore_x_init_count; - if (!_ecore_x_disp) return _ecore_x_init_count; + 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); + XCloseDisplay(_ecore_x_disp); else - close(ConnectionNumber(_ecore_x_disp)); + { + 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_main_fd_handler_del(_ecore_x_fd_handler_handle); _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(); - if (_ecore_x_init_count < 0) _ecore_x_init_count = 0; + + 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; } @@ -439,7 +737,7 @@ _ecore_x_shutdown(int close_display) * and any event handlers for it are removed. * * @return The number of times the library has been initialized without - * being shut down. + * being shut down. 0 is returned if an error occurs. * @ingroup Ecore_X_Init_Group */ EAPI int @@ -486,12 +784,95 @@ ecore_x_display_get(void) 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. @@ -502,7 +883,9 @@ ecore_x_fd_get(void) EAPI void ecore_x_double_click_time_set(double t) { - if (t < 0.0) t = 0.0; + if (t < 0.0) + t = 0.0; + _ecore_x_double_click_time = t; } @@ -534,6 +917,7 @@ ecore_x_double_click_time_get(void) EAPI void ecore_x_flush(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XFlush(_ecore_x_disp); } @@ -545,6 +929,7 @@ ecore_x_flush(void) EAPI void ecore_x_sync(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XSync(_ecore_x_disp, False); } @@ -565,19 +950,20 @@ ecore_x_killall(Ecore_X_Window root) 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)) + &children_r, &num_children) && (num_children > 0)) { - for (j = 0; j < num_children; ++j) - { - XKillClient(_ecore_x_disp, children_r[j]); - } - - XFree(children_r); + 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); @@ -593,6 +979,7 @@ ecore_x_killall(Ecore_X_Window root) EAPI void ecore_x_kill(Ecore_X_Window win) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XKillClient(_ecore_x_disp, win); } @@ -605,101 +992,141 @@ ecore_x_current_time_get(void) return _ecore_x_event_last_time; } -static int -_ecore_x_fd_handler(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +/** + * 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); - - /* Filter event for XIM */ - if (XFilterEvent(&ev, ev.xkey.window)) continue; - - if ((ev.type >= 0) && (ev.type < _ecore_x_event_handlers_num)) - { - if (_ecore_x_event_handlers[ev.type]) - _ecore_x_event_handlers[ev.type] (&ev); - } + 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 1; + return ECORE_CALLBACK_RENEW; } -static int -_ecore_x_fd_handler_buf(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__) +static Eina_Bool +_ecore_x_fd_handler_buf(void *data, + Ecore_Fd_Handler *fd_handler __UNUSED__) { Display *d; d = data; - if (XPending(d)) return 1; - return 0; + 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 - }; - + 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 = 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; - } - } - } + 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; -} - - - - - - - - - - - - - - - - - - - + if (mod->modifiermap) + XFree(mod->modifiermap); + XFree(mod); + } + return 0; +} /*****************************************************************************/ /*****************************************************************************/ @@ -722,108 +1149,122 @@ ecore_x_window_root_list(int *num_ret) Ecore_X_Window *roots; #ifdef ECORE_XPRINT int xp_base, xp_err_base; -#endif - - if (!num_ret) return NULL; +#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((num - overlap) * sizeof(Window)); - 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); - } + 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); + 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 + +#else /* ifdef ECORE_XPRINT */ num = ScreenCount(_ecore_x_disp); roots = malloc(num * sizeof(Window)); - if (!roots) return NULL; + if (!roots) + return NULL; + *num_ret = num; for (i = 0; i < num; i++) roots[i] = RootWindow(_ecore_x_disp, i); -#endif +#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 (!(roots)) return 0; + if (num > 0) - root = roots[0]; + root = roots[0]; else - root = 0; + root = 0; free(roots); return root; + */ } - static void _ecore_x_window_manage_error(void *data); static int _ecore_x_window_manage_failed = 0; @@ -835,114 +1276,98 @@ _ecore_x_window_manage_error(void *data __UNUSED__) _ecore_x_window_manage_failed = 1; } -EAPI int +EAPI Eina_Bool ecore_x_window_manage(Ecore_X_Window win) { - XWindowAttributes att; - - if (XGetWindowAttributes(_ecore_x_disp, win, &att) != True) return 0; + 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); + 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 0; + _ecore_x_window_manage_failed = 0; + return EINA_FALSE; } - return 1; + + return EINA_TRUE; } EAPI void ecore_x_window_container_manage(Ecore_X_Window win) { - XSelectInput(_ecore_x_disp, win, - SubstructureRedirectMask | - SubstructureNotifyMask); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + SubstructureRedirectMask | + SubstructureNotifyMask); } EAPI void ecore_x_window_client_manage(Ecore_X_Window win) { - XSelectInput(_ecore_x_disp, win, - PropertyChangeMask | + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSelectInput(_ecore_x_disp, win, + PropertyChangeMask | // ResizeRedirectMask | - FocusChangeMask | - ColormapChangeMask | - VisibilityChangeMask | - StructureNotifyMask - ); + 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); + 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); + PropertyChangeMask | + FocusChangeMask | + ColormapChangeMask | + VisibilityChangeMask | + StructureNotifyMask | + SubstructureNotifyMask); XShapeSelectInput(_ecore_x_disp, win, ShapeNotifyMask); } -/** - * 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) +EAPI Eina_Bool +ecore_x_window_attributes_get(Ecore_X_Window win, + Ecore_X_Window_Attributes *att_ret) { - if (!_ecore_x_disp) return 0; - 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; - 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]; -} - - - - + XWindowAttributes att; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) + return EINA_FALSE; -EAPI int -ecore_x_window_attributes_get(Ecore_X_Window win, Ecore_X_Window_Attributes *att_ret) -{ - XWindowAttributes att; - - if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) return 0; memset(att_ret, 0, sizeof(Ecore_X_Window_Attributes)); att_ret->root = att.root; att_ret->x = att.x; @@ -951,11 +1376,21 @@ ecore_x_window_attributes_get(Ecore_X_Window win, Ecore_X_Window_Attributes *att 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; + 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; @@ -963,185 +1398,240 @@ ecore_x_window_attributes_get(Ecore_X_Window win, Ecore_X_Window_Attributes *att att_ret->pixel_gravity = att.bit_gravity; att_ret->colormap = att.colormap; att_ret->visual = att.visual; - return 1; + 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_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; - + 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; - } + &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); + 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 int -ecore_x_pointer_control_set(int accel_num, int accel_denom, int threshold) +EAPI Eina_Bool +ecore_x_pointer_control_set(int accel_num, + int accel_denom, + int threshold) { - return XChangePointerControl(_ecore_x_disp, 1, 1, - accel_num, accel_denom, 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 int -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) { - return XGetPointerControl(_ecore_x_disp, - accel_num, accel_denom, threshold); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return (XSetPointerMapping(_ecore_x_disp, map, nmap) == MappingSuccess) ? EINA_TRUE : EINA_FALSE; } -EAPI int +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 1; - return 0; + ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + None, None, CurrentTime) == GrabSuccess) + return EINA_TRUE; + + return EINA_FALSE; } -EAPI int +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 1; - return 0; + 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 int -ecore_x_pointer_warp(Ecore_X_Window win, int x, int y) +EAPI Eina_Bool +ecore_x_pointer_warp(Ecore_X_Window win, + int x, + int y) { - return XWarpPointer(_ecore_x_disp, None, win, 0, 0, 0, 0, x, y); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return XWarpPointer(_ecore_x_disp, None, win, 0, 0, 0, 0, x, y) ? EINA_TRUE : EINA_FALSE; } -EAPI int +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 1; - return 0; + GrabModeAsync, GrabModeAsync, + CurrentTime) == GrabSuccess) + return EINA_TRUE; + + return EINA_FALSE; } EAPI void ecore_x_keyboard_ungrab(void) { - XUngrabKeyboard(_ecore_x_disp, CurrentTime); + 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); + 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; + _ecore_x_grab_count = 0; if (_ecore_x_grab_count == 0) - { - XUngrabServer(_ecore_x_disp); - XSync(_ecore_x_disp, False); - } + XUngrabServer(_ecore_x_disp); } -int _ecore_window_grabs_num = 0; -Window *_ecore_window_grabs = NULL; -int (*_ecore_window_grab_replay_func) (void *data, int event_type, void *event); -void *_ecore_window_grab_replay_data; +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(int (*func) (void *data, int event_type, void *event), void *data) +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; - +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 = mod; - if (any_mod) m = AnyModifier; + 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; + 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); + win, False, ev, GrabModeSync, GrabModeAsync, None, None); _ecore_window_grabs_num++; - _ecore_window_grabs = realloc(_ecore_window_grabs, - _ecore_window_grabs_num * sizeof(Window)); + 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) +_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; @@ -1159,89 +1649,120 @@ 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--; - _ecore_window_grabs = realloc(_ecore_window_grabs, - _ecore_window_grabs_num * sizeof(Window)); - } + 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; - +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 = mod; - if (any_mod) m = AnyModifier; + 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; + 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; +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; - +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)); + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return; + + keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key)); } - if (keycode == 0) return; - - m = mod; - if (any_mod) m = AnyModifier; + + 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; + 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); + win, False, GrabModeSync, GrabModeAsync); _ecore_key_grabs_num++; - _ecore_key_grabs = realloc(_ecore_key_grabs, - _ecore_key_grabs_num * sizeof(Window)); + 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; } @@ -1249,54 +1770,74 @@ 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--; - _ecore_key_grabs = realloc(_ecore_key_grabs, - _ecore_key_grabs_num * sizeof(Window)); - } + 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) +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; + 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)); + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return; + + keycode = XKeysymToKeycode(_ecore_x_disp, XStringToKeysym(key)); } - if (keycode == 0) return; - - m = mod; - if (any_mod) m = AnyModifier; + + 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; + 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); @@ -1307,32 +1848,39 @@ ecore_x_window_key_ungrab(Ecore_X_Window win, const char *key, * * @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 !0 on success. + * @return @c EINA_TRUE on success @c EINA_FALSE otherwise. */ -EAPI int -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_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; + XEvent xev; - 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; + 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); + return XSendEvent(_ecore_x_disp, win, False, mask, &xev) ? EINA_TRUE : EINA_FALSE; } /** @@ -1341,36 +1889,43 @@ ecore_x_client_message32_send(Ecore_X_Window win, Ecore_X_Atom type, * @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 20. + * @param len Number of data bytes, max @c 20. * - * @return !0 on success. + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. */ -EAPI int -ecore_x_client_message8_send(Ecore_X_Window win, Ecore_X_Atom type, - const void *data, int len) +EAPI Eina_Bool +ecore_x_client_message8_send(Ecore_X_Window win, + Ecore_X_Atom type, + const void *data, + int len) { - XEvent xev; + 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; - 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); + 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); + return XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev) ? EINA_TRUE : EINA_FALSE; } -EAPI int -ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y) +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; @@ -1385,17 +1940,21 @@ ecore_x_mouse_move_send(Ecore_X_Window win, int x, int y) xev.xmotion.state = 0; xev.xmotion.is_hint = 0; xev.xmotion.same_screen = 1; - return XSendEvent(_ecore_x_disp, win, True, PointerMotionMask, &xev); + return XSendEvent(_ecore_x_disp, win, True, PointerMotionMask, &xev) ? EINA_TRUE : EINA_FALSE; } -EAPI int -ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b) +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; @@ -1410,17 +1969,21 @@ ecore_x_mouse_down_send(Ecore_X_Window win, int x, int y, int b) xev.xbutton.state = 1 << b; xev.xbutton.button = b; xev.xbutton.same_screen = 1; - return XSendEvent(_ecore_x_disp, win, True, ButtonPressMask, &xev); + return XSendEvent(_ecore_x_disp, win, True, ButtonPressMask, &xev) ? EINA_TRUE : EINA_FALSE; } -EAPI int -ecore_x_mouse_up_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) { 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; @@ -1435,40 +1998,219 @@ ecore_x_mouse_up_send(Ecore_X_Window win, int x, int y, int b) xev.xbutton.state = 0; xev.xbutton.button = b; xev.xbutton.same_screen = 1; - return XSendEvent(_ecore_x_disp, win, True, ButtonReleaseMask, &xev); + 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) +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; + 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) +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; - - ret = XQueryPointer(_ecore_x_disp, win, &rwin, &cwin, &rx, &ry, &wx, &wy, &mask); - if (!ret) wx = wy = -1; + + 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 index 0ca85c1..6518264 100644 --- a/src/lib/ecore_x/xlib/ecore_x_atoms.c +++ b/src/lib/ecore_x/xlib/ecore_x_atoms.c @@ -1,203 +1,100 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#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 "config.h" #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" #include "Ecore_X_Atoms.h" - #include "ecore_x_atoms_decl.h" -typedef struct -{ - const char *name; - Ecore_X_Atom *atom; -} Atom_Item; - void _ecore_x_atoms_init(void) { - const Atom_Item 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 }, - - { "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_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_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_PRIMARY }, - { "PRIMARY", &ECORE_X_ATOM_SELECTION_SECONDARY }, - { "SECONDARY", &ECORE_X_ATOM_SELECTION_CLIPBOARD }, - { "_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 } - }; Atom *atoms; char **names; int i, num; - num = sizeof(items) / sizeof(Atom_Item); + 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 *)items[i].name; + 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++) *(items[i].atom) = atoms[i]; + 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 index 486d042..b919db9 100644 --- a/src/lib/ecore_x/xlib/ecore_x_composite.c +++ b/src/lib/ecore_x/xlib/ecore_x_composite.c @@ -1,27 +1,176 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ #include "ecore_x_private.h" #include "Ecore_X.h" -static int _composite_available; +static Eina_Bool _composite_available = EINA_FALSE; void _ecore_x_composite_init(void) { - _composite_available = 0; + _composite_available = EINA_FALSE; #ifdef ECORE_XCOMPOSITE int major, minor; if (XCompositeQueryVersion(_ecore_x_disp, &major, &minor)) - _composite_available = 1; + { +# 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 int +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 index d420a48..a968c56 100644 --- a/src/lib/ecore_x/xlib/ecore_x_cursor.c +++ b/src/lib/ecore_x/xlib/ecore_x_cursor.c @@ -1,192 +1,211 @@ -#include "ecore_x_private.h" +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ +#include -EAPI int +#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) +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++) - { + 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]; + xci->pixels[i] = pixels[i]; // (a << 24) | (r << 16) | (g << 8) | (b); - } - c = XcursorImageLoadCursor(_ecore_x_disp, xci); - XcursorImageDestroy(xci); - return c; - } + } + c = XcursorImageLoadCursor(_ecore_x_disp, xci); + XcursorImageDestroy(xci); + return c; + } } else -#endif - { - 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; - } +#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); } @@ -198,6 +217,7 @@ ecore_x_cursor_free(Ecore_X_Cursor c) 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); } @@ -206,18 +226,21 @@ EAPI void ecore_x_cursor_size_set(int size) { #ifdef ECORE_XCURSOR + LOGFN(__FILE__, __LINE__, __FUNCTION__); XcursorSetDefaultSize(_ecore_x_disp, size); -#else +#else /* ifdef ECORE_XCURSOR */ size = 0; -#endif +#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 +#else /* ifdef ECORE_XCURSOR */ return 0; -#endif +#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 index 3507ce2..b094f85 100644 --- a/src/lib/ecore_x/xlib/ecore_x_damage.c +++ b/src/lib/ecore_x/xlib/ecore_x_damage.c @@ -1,14 +1,14 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ #include "ecore_x_private.h" #include "Ecore_X.h" -static int _damage_available; +static Eina_Bool _damage_available = EINA_FALSE; #ifdef ECORE_XDAMAGE static int _damage_major, _damage_minor; -#endif +#endif /* ifdef ECORE_XDAMAGE */ void _ecore_x_damage_init(void) @@ -17,47 +17,55 @@ _ecore_x_damage_init(void) _damage_major = 1; _damage_minor = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (XDamageQueryVersion(_ecore_x_disp, &_damage_major, &_damage_minor)) - _damage_available = 1; + _damage_available = EINA_TRUE; else - _damage_available = 0; -#else - _damage_available = 0; -#endif + _damage_available = EINA_FALSE; + +#else /* ifdef ECORE_XDAMAGE */ + _damage_available = EINA_FALSE; +#endif /* ifdef ECORE_XDAMAGE */ } -EAPI int +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) +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 +#else /* ifdef ECORE_XDAMAGE */ return 0; -#endif +#endif /* ifdef ECORE_XDAMAGE */ } EAPI void -ecore_x_damage_del(Ecore_X_Damage damage) +ecore_x_damage_free(Ecore_X_Damage damage) { #ifdef ECORE_XDAMAGE + LOGFN(__FILE__, __LINE__, __FUNCTION__); XDamageDestroy(_ecore_x_disp, damage); -#endif +#endif /* ifdef ECORE_XDAMAGE */ } EAPI void -ecore_x_damage_subtract(Ecore_X_Damage damage, Ecore_X_Region repair, Ecore_X_Region parts) +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 +#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 index 61a64df..372470a 100644 --- a/src/lib/ecore_x/xlib/ecore_x_dnd.c +++ b/src/lib/ecore_x/xlib/ecore_x_dnd.c @@ -1,6 +1,10 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -20,33 +24,44 @@ static int _ecore_x_dnd_init_count = 0; typedef struct _Version_Cache_Item { Ecore_X_Window win; - int ver; + 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)); - _source->version = ECORE_X_DND_VERSION; - _source->win = None; - _source->dest = None; - _source->state = ECORE_X_DND_SOURCE_IDLE; - - _target = calloc(1, sizeof(Ecore_X_DND_Target)); - _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(); + _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++; @@ -61,54 +76,72 @@ _ecore_x_dnd_shutdown(void) if (_source) free(_source); + _source = NULL; if (_target) free(_target); + _target = NULL; _ecore_x_dnd_init_count = 0; } -static int -_ecore_x_dnd_converter_copy(char *target, void *data, int size, void **data_ret, int *size_ret) +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 0; + return EINA_FALSE; mystr = calloc(1, size + 1); - if (!mystr) return 0; + if (!mystr) + return EINA_FALSE; + memcpy(mystr, data, size); - if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, &text_prop) == Success) + if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, + &text_prop) == Success) { - int bufsize = strlen(text_prop.value) + 1; - *data_ret = malloc(bufsize); - memcpy(*data_ret, text_prop.value, bufsize); - *size_ret = bufsize; - XFree(text_prop.value); - free(mystr); - return 1; + 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 0; + free(mystr); + return EINA_FALSE; } } EAPI void -ecore_x_dnd_aware_set(Ecore_X_Window win, int on) +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); + XA_ATOM, 32, &prop_data, 1); else ecore_x_window_prop_property_del(win, ECORE_X_ATOM_XDND_AWARE); } @@ -118,62 +151,76 @@ 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 (_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; - _version_cache = realloc(_version_cache, _version_cache_alloc * sizeof(Version_Cache_Item)); - _version_cache[_version_cache_num - 1].win = win; - _version_cache[_version_cache_num - 1].ver = version; - } - return version; + 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; - _version_cache = realloc(_version_cache, _version_cache_alloc * sizeof(Version_Cache_Item)); - _version_cache[_version_cache_num - 1].win = win; - _version_cache[_version_cache_num - 1].ver = 0; + _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 int -ecore_x_dnd_type_isset(Ecore_X_Window win, const char *type) +EAPI Eina_Bool +ecore_x_dnd_type_isset(Ecore_X_Window win, + const char *type) { - int num, i, ret = 0; - unsigned char *data; - Ecore_X_Atom *atoms, atom; + 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)) + XA_ATOM, 32, &data, &num)) return ret; atom = ecore_x_atom_get(type); @@ -181,11 +228,11 @@ ecore_x_dnd_type_isset(Ecore_X_Window win, const char *type) for (i = 0; i < num; ++i) { - if (atom == atoms[i]) - { - ret = 1; - break; - } + if (atom == atoms[i]) + { + ret = EINA_TRUE; + break; + } } XFree(data); @@ -193,112 +240,152 @@ 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, int on) +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; + 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); + 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); + 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, char **types, unsigned int num_types) +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; + 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); - } + 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); + 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) +ecore_x_dnd_actions_set(Ecore_X_Window win, + Ecore_X_Atom *actions, + unsigned int num_actions) { - unsigned int i; - unsigned char *data = NULL; + 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); - } + 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); + 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) { @@ -311,90 +398,102 @@ _ecore_x_dnd_target_get(void) return _target; } -EAPI int -ecore_x_dnd_begin(Ecore_X_Window source, unsigned char *data, int size) +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 0; + return EINA_FALSE; /* Take ownership of XdndSelection */ if (!ecore_x_selection_xdnd_set(source, data, size)) - return 0; + return EINA_FALSE; if (_version_cache) { - free(_version_cache); - _version_cache = NULL; - _version_cache_num = 0; - _version_cache_alloc = 0; + 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 1; + return EINA_TRUE; } -EAPI int +EAPI Eina_Bool ecore_x_dnd_drop(void) { XEvent xev; - int status = 0; + 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 = 1; - } - 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; - } + 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; + /* 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(int will_accept, int suppress, Ecore_X_Rectangle rectangle, Ecore_X_Atom action) +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; @@ -409,6 +508,7 @@ ecore_x_dnd_send_status(int will_accept, int suppress, Ecore_X_Rectangle rectang xev.xclient.data.l[1] = 0; if (will_accept) xev.xclient.data.l[1] |= 0x1UL; + if (!suppress) xev.xclient.data.l[1] |= 0x2UL; @@ -422,13 +522,13 @@ ecore_x_dnd_send_status(int will_accept, int suppress, Ecore_X_Rectangle rectang if (will_accept) { - xev.xclient.data.l[4] = action; - _target->accepted_action = action; + xev.xclient.data.l[4] = action; + _target->accepted_action = action; } else { - xev.xclient.data.l[4] = None; - _target->accepted_action = action; + xev.xclient.data.l[4] = None; + _target->accepted_action = action; } XSendEvent(_ecore_x_disp, _target->source, False, 0, &xev); @@ -437,11 +537,12 @@ ecore_x_dnd_send_status(int will_accept, int suppress, Ecore_X_Rectangle rectang EAPI void ecore_x_dnd_send_finished(void) { - XEvent xev; + 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; @@ -453,21 +554,39 @@ ecore_x_dnd_send_finished(void) xev.xclient.data.l[2] = 0; if (_target->will_accept) { - xev.xclient.data.l[1] |= 0x1UL; - xev.xclient.data.l[2] = _target->accepted_action; + 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) +_ecore_x_dnd_drag(Ecore_X_Window root, + int x, + int y) { - XEvent xev; - Ecore_X_Window win; + XEvent xev; + Ecore_X_Window win; Ecore_X_Window *skip; - int num; + Ecore_X_Xdnd_Position pos; + int num; if (_source->state != ECORE_X_DND_SOURCE_DRAGGING) return; @@ -495,74 +614,93 @@ _ecore_x_dnd_drag(Ecore_X_Window root, int x, int y) /* 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; + 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; + 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; - } + 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 index d4dac43..23349f4 100644 --- a/src/lib/ecore_x/xlib/ecore_x_dpms.c +++ b/src/lib/ecore_x/xlib/ecore_x_dpms.c @@ -1,10 +1,10 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ #include "ecore_x_private.h" -static int _dpms_available; +static Eina_Bool _dpms_available = EINA_FALSE; void _ecore_x_dpms_init(void) @@ -16,12 +16,13 @@ _ecore_x_dpms_init(void) _dpms_minor = 0; if (DPMSGetVersion(_ecore_x_disp, &_dpms_major, &_dpms_minor)) - _dpms_available = 1; + _dpms_available = EINA_TRUE; else - _dpms_available = 0; -#else - _dpms_available = 0; -#endif + _dpms_available = EINA_FALSE; + +#else /* ifdef ECORE_XDPMS */ + _dpms_available = EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ } /** @@ -35,7 +36,7 @@ _ecore_x_dpms_init(void) * @return @c 1 if the X DPMS extension is available, @c 0 otherwise. * @ingroup Ecore_X_DPMS_Group */ -EAPI int +EAPI Eina_Bool ecore_x_dpms_query(void) { return _dpms_available; @@ -46,14 +47,15 @@ ecore_x_dpms_query(void) * @return @c 1 if the X server is capable of DPMS, @c 0 otherwise. * @ingroup Ecore_X_DPMS_Group */ -EAPI int +EAPI Eina_Bool ecore_x_dpms_capable_get(void) { #ifdef ECORE_XDPMS - return DPMSCapable(_ecore_x_disp); -#else - return 0; -#endif + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return DPMSCapable(_ecore_x_disp) ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XDPMS */ + return EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ } /** @@ -61,18 +63,19 @@ ecore_x_dpms_capable_get(void) * @return @c 1 if DPMS is enabled, @c 0 otherwise. * @ingroup Ecore_X_DPMS_Group */ -EAPI int +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; -#else - return 0; -#endif + return state ? EINA_TRUE : EINA_FALSE; +#else /* ifdef ECORE_XDPMS */ + return EINA_FALSE; +#endif /* ifdef ECORE_XDPMS */ } /** @@ -84,11 +87,13 @@ 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 + +#endif /* ifdef ECORE_XDPMS */ } /** @@ -99,12 +104,15 @@ ecore_x_dpms_enabled_set(int enabled) * @ingroup Ecore_X_DPMS_Group */ EAPI void -ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned int *off) +ecore_x_dpms_timeouts_get(unsigned int *standby, + unsigned int *suspend, + unsigned int *off) { #ifdef ECORE_XDPMS - DPMSGetTimeouts(_ecore_x_disp, (unsigned short *)standby, - (unsigned short *)suspend, (unsigned short *)off); -#endif + LOGFN(__FILE__, __LINE__, __FUNCTION__); + DPMSGetTimeouts(_ecore_x_disp, (unsigned short *)standby, + (unsigned short *)suspend, (unsigned short *)off); +#endif /* ifdef ECORE_XDPMS */ } /** @@ -114,14 +122,17 @@ ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned * @param off Amount of time of inactivity before the monitor is shut off. * @ingroup Ecore_X_DPMS_Group */ -EAPI int -ecore_x_dpms_timeouts_set(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) { #ifdef ECORE_XDPMS - return DPMSSetTimeouts(_ecore_x_disp, standby, suspend, off); -#else - return 0; -#endif + 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 */ } /** @@ -130,16 +141,17 @@ ecore_x_dpms_timeouts_set(unsigned int standby, unsigned int suspend, unsigned i * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int -ecore_x_dpms_timeout_standby_get() +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 +#else /* ifdef ECORE_XDPMS */ return 0; -#endif +#endif /* ifdef ECORE_XDPMS */ } /** @@ -149,16 +161,17 @@ ecore_x_dpms_timeout_standby_get() * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int -ecore_x_dpms_timeout_suspend_get() +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 +#else /* ifdef ECORE_XDPMS */ return 0; -#endif +#endif /* ifdef ECORE_XDPMS */ } /** @@ -168,21 +181,22 @@ ecore_x_dpms_timeout_suspend_get() * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int -ecore_x_dpms_timeout_off_get() +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 +#else /* ifdef ECORE_XDPMS */ return 0; -#endif +#endif /* ifdef ECORE_XDPMS */ } /** * Sets the standby timeout (in unit of seconds). - * @param new_standby Amount of time of inactivity before standby mode will be invoked. + * @param new_timeout Amount of time of inactivity before standby mode will be invoked. * @ingroup Ecore_X_DPMS_Group */ EAPI void @@ -191,14 +205,15 @@ 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 +#endif /* ifdef ECORE_XDPMS */ } /** * Sets the suspend timeout (in unit of seconds). - * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. + * @param new_timeout Amount of time of inactivity before the screen is placed into suspend mode. * @ingroup Ecore_X_DPMS_Group */ EAPI void @@ -207,14 +222,15 @@ 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 +#endif /* ifdef ECORE_XDPMS */ } /** * Sets the off timeout (in unit of seconds). - * @param off Amount of time of inactivity before the monitor is shut off. + * @param new_timeout Amount of time of inactivity before the monitor is shut off. * @ingroup Ecore_X_DPMS_Group */ EAPI void @@ -223,7 +239,9 @@ 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 +#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 index efc1c9c..d1b4111 100644 --- a/src/lib/ecore_x/xlib/ecore_x_drawable.c +++ b/src/lib/ecore_x/xlib/ecore_x_drawable.c @@ -1,17 +1,15 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#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. @@ -22,25 +20,37 @@ * @ingroup Ecore_X_Drawable_Group */ EAPI void -ecore_x_drawable_geometry_get(Ecore_X_Drawable d, int *x, int *y, int *w, int *h) +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; + 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; + { + 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; } /** @@ -52,15 +62,16 @@ 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) { - Window dummy_win; - int dummy_x, dummy_y; - unsigned int dummy_w, dummy_h, border_ret, dummy_depth; + 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; + border_ret = 0; - return (int) border_ret; + return (int)border_ret; } /** @@ -72,13 +83,36 @@ ecore_x_drawable_border_width_get(Ecore_X_Drawable d) 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; + 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; + depth_ret = 0; - return (int) depth_ret; + 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 index e36d04a..ea17e64 100644 --- a/src/lib/ecore_x/xlib/ecore_x_e.c +++ b/src/lib/ecore_x/xlib/ecore_x_e.c @@ -1,10 +1,11 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * OLD E hints */ -#include "config.h" + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -16,10 +17,15 @@ 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) +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; @@ -28,34 +34,75 @@ 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, int is_keyboard) +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); + &is_keyboard, 1); } -EAPI int +EAPI Eina_Bool ecore_x_e_virtual_keyboard_get(Ecore_X_Window win) { unsigned int val; - - if (!ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_E_VIRTUAL_KEYBOARD, &val, 1)) - return 0; - return 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_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; } @@ -64,47 +111,1534 @@ _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; - default: return 0; + 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_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); + &atom, 1); } EAPI Ecore_X_Virtual_Keyboard_State ecore_x_e_virtual_keyboard_state_get(Ecore_X_Window win) { - Ecore_X_Atom atom; - int num; - + 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)) + &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) +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); + 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_access_action_up_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_UP, + 0, 0, 0); +} + +EAPI void +ecore_x_e_illume_access_action_down_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_DOWN, + 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 index 3de31d6..f6eb075 100644 --- a/src/lib/ecore_x/xlib/ecore_x_error.c +++ b/src/lib/ecore_x/xlib/ecore_x_error.c @@ -1,27 +1,36 @@ -#include "ecore_private.h" +#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 void _ecore_x_error_handle(Display * d, XErrorEvent * ev); -static int _ecore_x_io_error_handle(Display *d); +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_func)(void *data) = NULL; static void *_error_data = NULL; -static void (*_io_error_func) (void *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 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) +ecore_x_error_handler_set(void (*func)(void *data), + const void *data) { _error_func = func; _error_data = (void *)data; @@ -31,11 +40,12 @@ ecore_x_error_handler_set(void (*func) (void *data), const 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) +ecore_x_io_error_handler_set(void (*func)(void *data), + const void *data) { _io_error_func = func; _io_error_data = (void *)data; @@ -44,7 +54,7 @@ ecore_x_io_error_handler_set(void (*func) (void *data), const 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 @@ -56,40 +66,61 @@ ecore_x_error_request_get(void) /** * 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); + XSetIOErrorHandler((XIOErrorHandler)_ecore_x_io_error_handle); } -static void -_ecore_x_error_handle(Display *d, XErrorEvent *ev) +static int +_ecore_x_error_handle(Display *d, + XErrorEvent *ev) { - if (d == _ecore_x_disp) + if (d == _ecore_x_disp) { - _error_request_code = ev->request_code; - _error_code = ev->error_code; - if (_error_func) _error_func(_error_data); + _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 (d == _ecore_x_disp) { - if (_io_error_func) _io_error_func(_io_error_data); - else exit(-1); + 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 index 59bacb2..7d685cf 100644 --- a/src/lib/ecore_x/xlib/ecore_x_events.c +++ b/src/lib/ecore_x/xlib/ecore_x_events.c @@ -1,10 +1,15 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include +#include + #include -#include "ecore_private.h" #include "Ecore.h" +#include "ecore_private.h" #include "ecore_x_private.h" #include "Ecore_X.h" #include "Ecore_X_Atoms.h" @@ -15,147 +20,125 @@ #ifndef CODESET #define CODESET "INVALID" -#endif - -#if 0 -static void _ecore_x_event_free_window_prop_name_class_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_title_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_visible_title_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_icon_name_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_visible_icon_name_change(void *data, void *ev); -static void _ecore_x_event_free_window_prop_client_machine_change(void *data, void *ev); -#endif -static void _ecore_x_event_free_key_down(void *data, void *ev); -static void _ecore_x_event_free_key_up(void *data, void *ev); - -static Window _ecore_x_mouse_down_last_win = 0; -static Window _ecore_x_mouse_down_last_last_win = 0; -static Window _ecore_x_mouse_down_last_event_win = 0; -static Window _ecore_x_mouse_down_last_last_event_win = 0; -static Time _ecore_x_mouse_down_last_time = 0; -static Time _ecore_x_mouse_down_last_last_time = 0; -static int _ecore_x_mouse_up_count = 0; -static int _ecore_x_mouse_down_did_triple = 0; - -EAPI void -ecore_x_event_mask_set(Ecore_X_Window w, Ecore_X_Event_Mask mask) -{ - XWindowAttributes attr; - XSetWindowAttributes s_attr; - - 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); -} +#endif /* ifndef CODESET */ -EAPI void -ecore_x_event_mask_unset(Ecore_X_Window w, Ecore_X_Event_Mask mask) +typedef struct _Ecore_X_Mouse_Down_Info { - XWindowAttributes attr; - XSetWindowAttributes s_attr; - - if (!w) - w = DefaultRootWindow(_ecore_x_disp); + 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; - 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); -} - -#if 0 static void -_ecore_x_event_free_window_prop_name_class_change(void *data, void *ev) +_ecore_x_mouse_down_info_clear(void) { - Ecore_X_Event_Window_Prop_Name_Class_Change *e; - - e = ev; - if (e->name) free(e->name); - if (e->clas) free(e->clas); - free(e); + 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; } -static void -_ecore_x_event_free_window_prop_title_change(void *data, void *ev) +void +_ecore_x_events_init(void) { - Ecore_X_Event_Window_Prop_Title_Change *e; - - e = ev; - if (e->title) free(e->title); - free(e); + //Actually, Nothing to do. } -static void -_ecore_x_event_free_window_prop_visible_title_change(void *data, void *ev) +void +_ecore_x_events_shutdown(void) { - Ecore_X_Event_Window_Prop_Visible_Title_Change *e; - - e = ev; - if (e->title) free(e->title); - free(e); + _ecore_x_mouse_down_info_clear(); } -static void -_ecore_x_event_free_window_prop_icon_name_change(void *data, void *ev) +static Ecore_X_Mouse_Down_Info * +_ecore_x_mouse_down_info_get(int dev) { - Ecore_X_Event_Window_Prop_Icon_Name_Change *e; - - e = ev; - if (e->name) free(e->name); - free(e); -} + Eina_Inlist *l = _ecore_x_mouse_down_info_list; + Ecore_X_Mouse_Down_Info *info = NULL; -static void -_ecore_x_event_free_window_prop_visible_icon_name_change(void *data, void *ev) -{ - Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change *e; - - e = ev; - if (e->name) free(e->name); - free(e); + //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_window_prop_client_machine_change(void *data, void *ev) +_ecore_x_event_free_mouse_move(void *data __UNUSED__, + void *ev) { - Ecore_X_Event_Window_Prop_Client_Machine_Change *e; - + Ecore_Event_Mouse_Move *e; + e = ev; - if (e->name) free(e->name); + if (_ecore_x_last_event_mouse_move) + { + _ecore_x_last_event_mouse_move_event = NULL; + _ecore_x_last_event_mouse_move = 0; + } + free(e); } -#endif -static void -_ecore_x_event_free_key_down(void *data __UNUSED__, void *ev) +EAPI void +ecore_x_event_mask_set(Ecore_X_Window w, + Ecore_X_Event_Mask mask) { - Ecore_X_Event_Key_Down *e; + XWindowAttributes attr; + XSetWindowAttributes s_attr; - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->key_compose) free(e->key_compose); - free(e); + 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); } -static void -_ecore_x_event_free_key_up(void *data __UNUSED__, void *ev) +EAPI void +ecore_x_event_mask_unset(Ecore_X_Window w, + Ecore_X_Event_Mask mask) { - Ecore_X_Event_Key_Up *e; + XWindowAttributes attr; + XSetWindowAttributes s_attr; - e = ev; - if (e->keyname) free(e->keyname); - if (e->keysymbol) free(e->keysymbol); - if (e->key_compose) free(e->key_compose); - free(e); + 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_free_xdnd_enter(void *data __UNUSED__, + void *ev) { Ecore_X_Event_Xdnd_Enter *e; int i; @@ -168,7 +151,8 @@ _ecore_x_event_free_xdnd_enter(void *data __UNUSED__, void *ev) } static void -_ecore_x_event_free_selection_notify(void *data __UNUSED__, void *ev) +_ecore_x_event_free_selection_notify(void *data __UNUSED__, + void *ev) { Ecore_X_Event_Selection_Notify *e; Ecore_X_Selection_Data *sel; @@ -177,114 +161,360 @@ _ecore_x_event_free_selection_notify(void *data __UNUSED__, void *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_x_event_handle_key_press(XEvent *xevent) +_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_X_Event_Key_Down *e; - char *keyname; - int val; - char buf[256]; - KeySym sym; - XComposeStatus status; + Ecore_Event_Mouse_Move *e; + Ecore_Event *event; - e = calloc(1, sizeof(Ecore_X_Event_Key_Down)); - if (!e) return; - keyname = XKeysymToString(XKeycodeToKeysym(xevent->xkey.display, - xevent->xkey.keycode, 0)); + 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(buf, sizeof(buf), "Keycode-%i", xevent->xkey.keycode); - keyname = buf; + snprintf(keyname_buffer, + sizeof(keyname_buffer), + "Keycode-%i", + xevent->keycode); + keyname = keyname_buffer; } - e->keyname = strdup(keyname); - if (!e->keyname) + + sym = 0; + key = NULL; + compose = NULL; + val = XLookupString(xevent, + compose_buffer, + sizeof(compose_buffer), + &sym, + &status); + if (val > 0) { - free(e); - return; + 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; } - val = XLookupString((XKeyEvent *)xevent, buf, sizeof(buf), &sym, &status); - if (val > 0) + + 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) { - buf[val] = 0; - e->key_compose = ecore_txt_convert(nl_langinfo(CODESET), "UTF-8", buf); + 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; + } + } } - else e->key_compose = NULL; - keyname = XKeysymToString(sym); - if (keyname) e->keysymbol = strdup(keyname); - else e->keysymbol = strdup(e->keyname); - if (!e->keysymbol) + + /* 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)) { - if (e->keyname) free(e->keyname); - if (e->key_compose) free(e->key_compose); - free(e); - return; + 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; } - if (xevent->xkey.subwindow) e->win = xevent->xkey.subwindow; - else e->win = xevent->xkey.window; - e->event_win = xevent->xkey.window; - e->time = xevent->xkey.time; - e->modifiers = xevent->xkey.state; - e->same_screen = xevent->xkey.same_screen; - e->root_win = xevent->xkey.root; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_KEY_DOWN, e, _ecore_x_event_free_key_down, NULL); + + 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_X_Event_Key_Up *e; - char *keyname; - int val; - char buf[256]; - KeySym sym; - XComposeStatus status; - - e = calloc(1, sizeof(Ecore_X_Event_Key_Up)); - if (!e) return; - keyname = XKeysymToString(XKeycodeToKeysym(xevent->xkey.display, - xevent->xkey.keycode, 0)); - if (!keyname) - { - snprintf(buf, sizeof(buf), "Keycode-%i", xevent->xkey.keycode); - keyname = buf; - } - e->keyname = strdup(keyname); - if (!e->keyname) - { - free(e); - return; - } - val = XLookupString((XKeyEvent *)xevent, buf, sizeof(buf), &sym, &status); - if (val > 0) - { - buf[val] = 0; - e->key_compose = ecore_txt_convert("ISO8859-1", "UTF-8", buf); - } - else e->key_compose = NULL; - keyname = XKeysymToString(sym); - if (keyname) e->keysymbol = strdup(keyname); - else e->keysymbol = strdup(e->keyname); - if (!e->keysymbol) - { - if (e->keyname) free(e->keyname); - if (e->key_compose) free(e->key_compose); - free(e); - return; - } - if (xevent->xkey.subwindow) e->win = xevent->xkey.subwindow; - else e->win = xevent->xkey.window; - e->event_win = xevent->xkey.window; - e->time = xevent->xkey.time; - e->modifiers = xevent->xkey.state; - e->same_screen = xevent->xkey.same_screen; - e->root_win = xevent->xkey.root; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_KEY_UP, e, _ecore_x_event_free_key_up, NULL); + _ecore_key_press(ECORE_EVENT_KEY_UP, (XKeyEvent *)xevent); } void @@ -292,435 +522,394 @@ _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_X_Event_Mouse_Wheel *e; - - e = malloc(sizeof(Ecore_X_Event_Mouse_Wheel)); - - if (!e) - return; - - e->modifiers = xevent->xbutton.state; - e->direction = 0; - e->z = 0; - if (xevent->xbutton.button == 4) - { - e->direction = 0; - e->z = -1; - } - else if (xevent->xbutton.button == 5) - { - e->direction = 0; - e->z = 1; - } - else if (xevent->xbutton.button == 6) - { - e->direction = 1; - e->z = -1; - } - else if (xevent->xbutton.button == 7) - { - e->direction = 1; - e->z = 1; - } - 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->win = xevent->xbutton.subwindow; - else - e->win = xevent->xbutton.window; - - e->event_win = xevent->xbutton.window; - e->same_screen = xevent->xbutton.same_screen; - e->root_win = xevent->xbutton.root; - e->time = xevent->xbutton.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_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)) - { - int replay = 0; - - if (_ecore_window_grab_replay_func) - replay = _ecore_window_grab_replay_func(_ecore_window_grab_replay_data, - ECORE_X_EVENT_MOUSE_WHEEL, - e); - if (replay) - XAllowEvents(xevent->xbutton.display, - ReplayPointer, - xevent->xbutton.time); - else - XAllowEvents(xevent->xbutton.display, - AsyncPointer, - xevent->xbutton.time); - break; - } - } + 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_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = xevent->xbutton.state; - 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->win = xevent->xbutton.subwindow; - else e->win = xevent->xbutton.window; - e->same_screen = xevent->xbutton.same_screen; - e->root_win = xevent->xbutton.root; - e->event_win = xevent->xbutton.window; - e->time = xevent->xbutton.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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Button_Down *e; - - if (_ecore_x_mouse_down_did_triple) - { - _ecore_x_mouse_down_last_win = 0; - _ecore_x_mouse_down_last_last_win = 0; - _ecore_x_mouse_down_last_event_win = 0; - _ecore_x_mouse_down_last_last_event_win = 0; - _ecore_x_mouse_down_last_time = 0; - _ecore_x_mouse_down_last_last_time = 0; - } - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Button_Down)); - if (!e) return; - e->button = xevent->xbutton.button; - e->modifiers = xevent->xbutton.state; - 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->win = xevent->xbutton.subwindow; - else e->win = xevent->xbutton.window; - e->same_screen = xevent->xbutton.same_screen; - e->root_win = xevent->xbutton.root; - e->event_win = xevent->xbutton.window; - e->time = xevent->xbutton.time; - if (e->win == e->event_win) - { - if (((int)(e->time - _ecore_x_mouse_down_last_time) <= - (int)(1000 * _ecore_x_double_click_time)) && - (e->win == _ecore_x_mouse_down_last_win) && - (e->event_win == _ecore_x_mouse_down_last_event_win) - ) - e->double_click = 1; - if (((int)(e->time - _ecore_x_mouse_down_last_last_time) <= - (int)(2 * 1000 * _ecore_x_double_click_time)) && - (e->win == _ecore_x_mouse_down_last_win) && - (e->win == _ecore_x_mouse_down_last_last_win) && - (e->event_win == _ecore_x_mouse_down_last_event_win) && - (e->event_win == _ecore_x_mouse_down_last_last_event_win) - ) - { - e->triple_click = 1; - _ecore_x_mouse_down_did_triple = 1; - } - else - _ecore_x_mouse_down_did_triple = 0; - } - if (!e->double_click && !e->triple_click) - _ecore_x_mouse_up_count = 0; - _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_BUTTON_DOWN, 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)) - { - int replay = 0; - - if (_ecore_window_grab_replay_func) - replay = _ecore_window_grab_replay_func(_ecore_window_grab_replay_data, - ECORE_X_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; - } - } - if (e->win == e->event_win) - { - if (!_ecore_x_mouse_down_did_triple) - { - _ecore_x_mouse_down_last_last_win = _ecore_x_mouse_down_last_win; - if (xevent->xbutton.subwindow) - _ecore_x_mouse_down_last_win = xevent->xbutton.subwindow; - else - _ecore_x_mouse_down_last_win = xevent->xbutton.window; - _ecore_x_mouse_down_last_last_event_win = _ecore_x_mouse_down_last_event_win; - _ecore_x_mouse_down_last_event_win = xevent->xbutton.window; - _ecore_x_mouse_down_last_last_time = _ecore_x_mouse_down_last_time; - _ecore_x_mouse_down_last_time = xevent->xbutton.time; - } - } - } + { + _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_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = xevent->xbutton.state; - 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->win = xevent->xbutton.subwindow; - else e->win = xevent->xbutton.window; - e->same_screen = xevent->xbutton.same_screen; - e->root_win = xevent->xbutton.root; - e->event_win = xevent->xbutton.window; - e->time = xevent->xbutton.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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Button_Up *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Button_Up)); - if (!e) return; - e->button = xevent->xbutton.button; - e->modifiers = xevent->xbutton.state; - 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->win = xevent->xbutton.subwindow; - else e->win = xevent->xbutton.window; - e->same_screen = xevent->xbutton.same_screen; - e->root_win = xevent->xbutton.root; - e->event_win = xevent->xbutton.window; - e->time = xevent->xbutton.time; - _ecore_x_mouse_up_count++; - if (e->win == e->event_win) - { - if ((_ecore_x_mouse_up_count >= 2) && - ((int)(e->time - _ecore_x_mouse_down_last_time) <= - (int)(1000 * _ecore_x_double_click_time)) && - (e->win == _ecore_x_mouse_down_last_win) && - (e->event_win == _ecore_x_mouse_down_last_event_win) - ) - e->double_click = 1; - if ((_ecore_x_mouse_up_count >= 3) && - ((int)(e->time - _ecore_x_mouse_down_last_last_time) <= - (int)(2 * 1000 * _ecore_x_double_click_time)) && - (e->win == _ecore_x_mouse_down_last_win) && - (e->win == _ecore_x_mouse_down_last_last_win) && - (e->event_win == _ecore_x_mouse_down_last_event_win) && - (e->event_win == _ecore_x_mouse_down_last_last_event_win) - ) - e->triple_click = 1; - } - _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_BUTTON_UP, e, NULL, NULL); - } + _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) { - Ecore_X_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->modifiers = xevent->xmotion.state; - e->x = xevent->xmotion.x; - e->y = xevent->xmotion.y; - e->root.x = xevent->xmotion.x_root; - e->root.y = xevent->xmotion.y_root; - if (xevent->xmotion.subwindow) e->win = xevent->xmotion.subwindow; - else e->win = xevent->xmotion.window; - e->same_screen = xevent->xmotion.same_screen; - e->root_win = xevent->xmotion.root; - e->event_win = xevent->xmotion.window; - e->time = xevent->xmotion.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; +/* + 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, e->root.x, e->root.y); - - ecore_event_add(ECORE_X_EVENT_MOUSE_MOVE, e, NULL, NULL); + _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_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->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; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_In *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_In)); - if (!e) return; - e->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); - } + _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_Event_Mouse_Move *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Move)); - if (!e) return; - e->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; - 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_MOVE, e, NULL, NULL); - } - { - Ecore_X_Event_Mouse_Out *e; - - e = calloc(1, sizeof(Ecore_X_Event_Mouse_Out)); - if (!e) return; - e->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); - } + _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; + 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; + + 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); @@ -730,22 +919,41 @@ 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; + 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; + + 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); @@ -754,16 +962,20 @@ _ecore_x_event_handle_focus_out(XEvent *xevent) void _ecore_x_event_handle_keymap_notify(XEvent *xevent __UNUSED__) { - /* FIXME: handle this event type */ + _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; + if (!e) + return; + e->win = xevent->xexpose.window; e->time = _ecore_x_event_last_time; e->x = xevent->xexpose.x; @@ -771,16 +983,19 @@ _ecore_x_event_handle_expose(XEvent *xevent) 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); + 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; + if (!e) + return; + e->win = xevent->xgraphicsexpose.drawable; e->time = _ecore_x_event_last_time; e->x = xevent->xgraphicsexpose.x; @@ -788,24 +1003,28 @@ _ecore_x_event_handle_graphics_expose(XEvent *xevent) 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); + 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; + if (!e) + return; + e->win = xevent->xvisibility.window; e->time = _ecore_x_event_last_time; if (xevent->xvisibility.state == VisibilityFullyObscured) - e->fully_obscured = 1; + e->fully_obscured = 1; else - e->fully_obscured = 0; + e->fully_obscured = 0; + ecore_event_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE, e, NULL, NULL); } } @@ -815,13 +1034,23 @@ _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; + if (!e) + return; + e->win = xevent->xcreatewindow.window; + e->parent = xevent->xcreatewindow.parent; if (xevent->xcreatewindow.override_redirect) - e->override = 1; + e->override = 1; else - e->override = 0; + 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); } @@ -830,23 +1059,33 @@ 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; + 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); + 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; + 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); } @@ -855,10 +1094,14 @@ 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; + 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); } @@ -867,9 +1110,12 @@ 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; + if (!e) + return; + e->win = xevent->xmaprequest.window; e->time = _ecore_x_event_last_time; e->parent = xevent->xmaprequest.parent; @@ -880,10 +1126,14 @@ 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; + 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); @@ -893,10 +1143,14 @@ 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; + 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; @@ -906,7 +1160,7 @@ _ecore_x_event_handle_configure_notify(XEvent *xevent) 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); + ecore_event_add(ECORE_X_EVENT_WINDOW_CONFIGURE, e, NULL, NULL); } void @@ -914,9 +1168,13 @@ _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; + 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; @@ -925,6 +1183,7 @@ _ecore_x_event_handle_configure_request(XEvent *xevent) 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) @@ -935,12 +1194,14 @@ _ecore_x_event_handle_configure_request(XEvent *xevent) 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 */ } @@ -949,8 +1210,11 @@ _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; + if (!e) + return; + e->win = xevent->xresizerequest.window; e->w = xevent->xresizerequest.width; e->h = xevent->xresizerequest.height; @@ -962,15 +1226,19 @@ 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; + 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->detail = ECORE_X_WINDOW_STACK_BELOW; + e->time = _ecore_x_event_last_time; ecore_event_add(ECORE_X_EVENT_WINDOW_STACK, e, NULL, NULL); } @@ -979,15 +1247,19 @@ 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; + 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->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); } @@ -995,103 +1267,14 @@ _ecore_x_event_handle_circulate_request(XEvent *xevent) void _ecore_x_event_handle_property_notify(XEvent *xevent) { -#if 0 /* for now i disabled this. nice idea though this is - it leaves a lot - * to be desired for efficiency that is better left to the app layer - */ - if (xevent->xproperty.atom == ECORE_X_ATOM_WM_CLASS) - { - Ecore_X_Event_Window_Prop_Name_Class_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Name_Class_Change)); - if (!e) return; - ecore_x_window_prop_name_class_get(xevent->xproperty.window, - &(e->name), &(e->clas)); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_NAME_CLASS_CHANGE, e, _ecore_x_event_free_window_prop_name_class_change, NULL); - } - else if ((xevent->xproperty.atom == ECORE_X_ATOM_WM_NAME) || (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_NAME)) - { - Ecore_X_Event_Window_Prop_Title_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Title_Change)); - if (!e) return; - e->title = ecore_x_window_prop_title_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_TITLE_CHANGE, e, _ecore_x_event_free_window_prop_title_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_VISIBLE_NAME) - { - Ecore_X_Event_Window_Prop_Visible_Title_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Visible_Title_Change)); - if (!e) return; - e->title = ecore_x_window_prop_visible_title_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_VISIBLE_TITLE_CHANGE, e, _ecore_x_event_free_window_prop_visible_title_change, NULL); - } - else if ((xevent->xproperty.atom == ECORE_X_ATOM_WM_ICON_NAME) || (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_ICON_NAME)) - { - Ecore_X_Event_Window_Prop_Icon_Name_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Icon_Name_Change)); - if (!e) return; - e->name = ecore_x_window_prop_icon_name_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_ICON_NAME_CHANGE, e, _ecore_x_event_free_window_prop_icon_name_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME) - { - Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Visible_Icon_Name_Change)); - if (!e) return; - e->name = ecore_x_window_prop_visible_icon_name_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_VISIBLE_ICON_NAME_CHANGE, e, _ecore_x_event_free_window_prop_visible_icon_name_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_WM_CLIENT_MACHINE) - { - Ecore_X_Event_Window_Prop_Client_Machine_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Client_Machine_Change)); - if (!e) return; - e->name = ecore_x_window_prop_client_machine_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_CLIENT_MACHINE_CHANGE, e, _ecore_x_event_free_window_prop_client_machine_change, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_PID) - { - Ecore_X_Event_Window_Prop_Pid_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Pid_Change)); - if (!e) return; - e->pid = ecore_x_window_prop_pid_get(xevent->xproperty.window); - e->time = xevent->xproperty.time; - _ecore_x_event_last_time = e->time; - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE, e, NULL, NULL); - } - else if (xevent->xproperty.atom == ECORE_X_ATOM_NET_WM_DESKTOP) - { - Ecore_X_Event_Window_Prop_Desktop_Change *e; - - e = calloc(1, sizeof(Ecore_X_Event_Window_Prop_Desktop_Change)); - if (!e) return; - e->desktop = ecore_x_window_prop_desktop_get(xevent->xproperty.window); - ecore_event_add(ECORE_X_EVENT_WINDOW_PROP_PID_CHANGE, e, NULL, NULL); - } - else -#endif + _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 = 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; @@ -1103,40 +1286,48 @@ _ecore_x_event_handle_property_notify(XEvent *xevent) void _ecore_x_event_handle_selection_clear(XEvent *xevent) { - Ecore_X_Selection_Intern *d; +// Ecore_X_Selection_Intern *d; Ecore_X_Event_Selection_Clear *e; Ecore_X_Atom sel; - if (!(d = _ecore_x_selection_get(xevent->xselectionclear.selection))) - return; - if (xevent->xselectionclear.time > d->time) + 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); + _ecore_x_selection_set(None, NULL, 0, + xevent->xselectionclear.selection); } - - /* Generate event for app cleanup */ + */ +/* Generate event for app cleanup */ e = malloc(sizeof(Ecore_X_Event_Selection_Clear)); e->win = xevent->xselectionclear.window; e->time = xevent->xselectionclear.time; - sel = xevent->xselectionclear.selection; + 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 + else if (sel == ECORE_X_ATOM_SELECTION_CLIPBOARD) e->selection = ECORE_X_SELECTION_CLIPBOARD; - ecore_event_add(ECORE_X_EVENT_SELECTION_CLEAR, e, NULL, NULL); + 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; - + 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. */ @@ -1152,74 +1343,94 @@ _ecore_x_event_handle_selection_request(XEvent *xevent) 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; - - if (!ecore_x_selection_convert(xevent->xselectionrequest.selection, - xevent->xselectionrequest.target, - &data)) - { - /* Refuse selection, conversion to requested target failed */ - property = None; - } - else - { - /* FIXME: This does not properly handle large data transfers */ - ecore_x_window_prop_property_set(xevent->xselectionrequest.requestor, - xevent->xselectionrequest.property, - xevent->xselectionrequest.target, - 8, data, sd->length); - property = xevent->xselectionrequest.property; - free(data); - } - - ecore_x_selection_notify_send(xevent->xselectionrequest.requestor, - xevent->xselectionrequest.selection, - xevent->xselectionrequest.target, - property, - xevent->xselectionrequest.time); - } + 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); + } } - return; } 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; - int format; + 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) - return; + 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; + 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; + 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) @@ -1231,13 +1442,12 @@ _ecore_x_event_handle_selection_notify(XEvent *xevent) else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) e->selection = ECORE_X_SELECTION_CLIPBOARD; else - { - free(e); - return; - } + 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); + ecore_event_add(ECORE_X_EVENT_SELECTION_NOTIFY, e, + _ecore_x_event_free_selection_notify, NULL); } void @@ -1245,21 +1455,26 @@ _ecore_x_event_handle_colormap_notify(XEvent *xevent) { Ecore_X_Event_Window_Colormap *e; - e = calloc(1,sizeof(Ecore_X_Event_Window_Colormap)); - if (!e) return; + _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 = 1; + e->installed = EINA_TRUE; else - e->installed = 0; + 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*/ @@ -1268,393 +1483,475 @@ _ecore_x_event_handle_client_message(XEvent *xevent) (xevent->xclient.format == 32) && (xevent->xclient.data.l[0] == (long)ECORE_X_ATOM_WM_DELETE_WINDOW)) { - Ecore_X_Event_Window_Delete_Request *e; + 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); - } + 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)) + (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); + 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; - unsigned long three; - - e = calloc(1, sizeof(Ecore_X_Event_Xdnd_Enter)); - if (!e) return; - - 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) - { - printf("DND: Requested version %d, we only support up to %d\n", target->version, - ECORE_X_DND_VERSION); - return; - } - - if ((three = 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; - if (!(ecore_x_window_prop_property_get(target->source, - ECORE_X_ATOM_XDND_TYPE_LIST, - XA_ATOM, - 32, - &data, - &num_ret))) - { - printf("DND: Could not fetch data type list from source window, aborting.\n"); - return; - } - types = (Ecore_X_Atom *)data; - e->types = calloc(num_ret, sizeof(char *)); - if (e->types) - { - 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) - { - 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); + 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; - - 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); - } + 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; - - 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); - } + 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; + Ecore_X_Event_Xdnd_Leave *e; + Ecore_X_DND_Target *target; - target = _ecore_x_dnd_target_get(); - if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) || - (target->win != xevent->xclient.window)) - return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); - target->state = ECORE_X_DND_TARGET_IDLE; + target = _ecore_x_dnd_target_get(); + if ((target->source != (Ecore_X_Window)xevent->xclient.data.l[0]) || + (target->win != xevent->xclient.window)) + return; - 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); - } + 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; - - 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); - } + 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; - int completed = 1; - - 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)) - { - /* Target successfully performed drop action */ - ecore_x_selection_xdnd_clear(); - source->state = ECORE_X_DND_SOURCE_IDLE; - } - else if (source->version >= 5) - { - completed = 0; - 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); + 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; - } - e->state[0] = _ecore_x_netwm_state_get(xevent->xclient.data.l[1]); - if (e->state[0] == ECORE_X_WINDOW_STATE_UNKNOWN) - { - char *name; - name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[1]); - if (name) - printf("Unknown state: %s\n", 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; - name = XGetAtomName(_ecore_x_disp, xevent->xclient.data.l[2]); - if (name) - printf("Unknown state: %s\n", name); - XFree(name); - } - e->source = xevent->xclient.data.l[3]; - - ecore_event_add(ECORE_X_EVENT_WINDOW_STATE_REQUEST, e, NULL, NULL); + 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)) + && (xevent->xclient.format == 32) + && (xevent->xclient.data.l[0] == IconicState)) { - Ecore_X_Event_Window_State_Request *e; + Ecore_X_Event_Window_State_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Window_State_Request)); + if (!e) + return; - 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; + 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); + 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)) + && (xevent->xclient.format == 32)) { - Ecore_X_Event_Desktop_Change *e; + 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]; + e = calloc(1, sizeof(Ecore_X_Event_Desktop_Change)); + if (!e) + return; - 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; + 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_FRAME_EXTENTS_REQUEST, e, NULL, NULL); + ecore_event_add(ECORE_X_EVENT_DESKTOP_CHANGE, 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)) + else if ((xevent->xclient.message_type == + ECORE_X_ATOM_NET_REQUEST_FRAME_EXTENTS)) { - Ecore_X_Event_Ping *e; + Ecore_X_Event_Frame_Extents_Request *e; + + e = calloc(1, sizeof(Ecore_X_Event_Frame_Extents_Request)); + if (!e) + return; - 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]; + e->win = xevent->xclient.window; - ecore_event_add(ECORE_X_EVENT_PING, e, NULL, NULL); + ecore_event_add(ECORE_X_EVENT_FRAME_EXTENTS_REQUEST, e, NULL, NULL); } - else if ((xevent->xclient.message_type == ECORE_X_ATOM_NET_STARTUP_INFO_BEGIN) && - (xevent->xclient.format == 8)) + 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_netwm_startup_info_begin(xevent->xclient.window, xevent->xclient.data.b); + 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); - } + (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)) + && (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]); + /* 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); + 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 __UNUSED__) +_ecore_x_event_handle_mapping_notify(XEvent *xevent) { - /* FIXME: handle this event type */ + 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 @@ -1662,12 +1959,37 @@ _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; + 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); } @@ -1677,20 +1999,25 @@ _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; + if (!e) + return; + e->win = screensaver_event->window; - if (screensaver_event->state == ScreenSaverOn) - e->on = 1; - else - e->on = 0; + 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 +#else /* ifdef ECORE_XSS */ xevent = NULL; -#endif +#endif /* ifdef ECORE_XSS */ } void @@ -1698,10 +2025,13 @@ _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; + if (!e) + return; + e->time = sync_counter_event->time; ecore_event_add(ECORE_X_EVENT_SYNC_COUNTER, e, NULL, NULL); } @@ -1712,10 +2042,13 @@ _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; + 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); @@ -1728,40 +2061,176 @@ _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)) - printf("ERROR: Can't update RR config!\n"); + ERR("Can't update RR config!"); e = calloc(1, sizeof(Ecore_X_Event_Screen_Change)); - if (!e) return; + if (!e) + return; + e->win = randr_event->window; e->root = randr_event->root; - e->width = randr_event->width; - e->height = randr_event->height; + 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); } -#endif + +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 */ - event = NULL; + + 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 + +#endif /* ifdef ECORE_XFIXES */ #ifdef ECORE_XDAMAGE void _ecore_x_event_handle_damage_notify(XEvent *event) { - XDamageNotifyEvent *damage_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; + if (!e) + return; e->level = damage_event->level; e->drawable = damage_event->drawable; @@ -1779,5 +2248,280 @@ _ecore_x_event_handle_damage_notify(XEvent *event) ecore_event_add(ECORE_X_EVENT_DAMAGE_NOTIFY, e, NULL, NULL); } -#endif +#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 index d4645a7..da0a6c3 100644 --- a/src/lib/ecore_x/xlib/ecore_x_fixes.c +++ b/src/lib/ecore_x/xlib/ecore_x_fixes.c @@ -1,6 +1,8 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include #include "ecore_x_private.h" #include "Ecore_X.h" @@ -8,7 +10,7 @@ static int _fixes_available; #ifdef ECORE_XFIXES static int _fixes_major, _fixes_minor; -#endif +#endif /* ifdef ECORE_XFIXES */ void _ecore_x_fixes_init(void) @@ -17,71 +19,107 @@ _ecore_x_fixes_init(void) _fixes_major = 3; _fixes_minor = 0; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (XFixesQueryVersion(_ecore_x_disp, &_fixes_major, &_fixes_minor)) - _fixes_available = 1; + { + _fixes_available = 1; + + ECORE_X_EVENT_FIXES_SELECTION_NOTIFY = ecore_event_type_new(); + } else _fixes_available = 0; -#else + +#else /* ifdef ECORE_XFIXES */ _fixes_available = 0; -#endif +#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) +_ecore_x_rectangle_ecore_to_x(Ecore_X_Rectangle *rects, + int num) { XRectangle *xrect; int i; - if (num == 0) return NULL; + if (num == 0) + return NULL; xrect = malloc(sizeof(XRectangle) * num); - if (!xrect) return NULL; + 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; + 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_x_to_ecore(XRectangle *xrect, + int num) { Ecore_X_Rectangle *rects; int i; - if (num == 0) return NULL; + if (num == 0) + return NULL; + rects = malloc(sizeof(Ecore_X_Rectangle) * num); - if (!rects) return NULL; + 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; + 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) +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 +#else /* ifdef ECORE_XFIXES */ return 0; -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI Ecore_X_Region @@ -90,24 +128,27 @@ 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 +#else /* ifdef ECORE_XFIXES */ return 0; -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI Ecore_X_Region -ecore_x_region_new_from_window(Ecore_X_Window win, Ecore_X_Region_Type type) +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 +#else /* ifdef ECORE_XFIXES */ return 0; -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI Ecore_X_Region @@ -116,11 +157,12 @@ 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 +#else /* ifdef ECORE_XFIXES */ return 0; -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI Ecore_X_Region @@ -129,139 +171,195 @@ 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 +#else /* ifdef ECORE_XFIXES */ return 0; -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_del(Ecore_X_Region region) +ecore_x_region_free(Ecore_X_Region region) { #ifdef ECORE_XFIXES + LOGFN(__FILE__, __LINE__, __FUNCTION__); XFixesDestroyRegion(_ecore_x_disp, region); -#endif +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_set(Ecore_X_Region region, Ecore_X_Rectangle *rects, int num) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_copy(Ecore_X_Region dest, Ecore_X_Region source) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_combine(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_intersect(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_subtract(Ecore_X_Region dest, Ecore_X_Region source1, Ecore_X_Region source2) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_invert(Ecore_X_Region dest, Ecore_X_Rectangle *bounds, Ecore_X_Region source) +ecore_x_region_invert(Ecore_X_Region dest, + Ecore_X_Rectangle *bounds, + Ecore_X_Region source) { #ifdef ECORE_XFIXES XRectangle *xbound; int num = 0; - while(bounds + num) num++; + 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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_translate(Ecore_X_Region region, int dx, int dy) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI void -ecore_x_region_extents(Ecore_X_Region dest, Ecore_X_Region source) +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 +#endif /* ifdef ECORE_XFIXES */ } EAPI Ecore_X_Rectangle * -ecore_x_region_fetch(Ecore_X_Region region, int *num, Ecore_X_Rectangle *bounds){ +ecore_x_region_fetch(Ecore_X_Region region, + int *num, + Ecore_X_Rectangle *bounds){ #ifdef ECORE_XFIXES - Ecore_X_Rectangle *rects; - XRectangle *xrect, xbound; - - 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 - return NULL; -#endif + 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) +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 +#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) +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 +#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) +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 - XFixesSetWindowShapeRegion(_ecore_x_disp, win, type, x_offset, y_offset, region); -#endif + 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) +ecore_x_region_picture_clip_set(Ecore_X_Region region, + Ecore_X_Picture picture, + int x_origin, + int y_origin) { #ifdef ECORE_XFIXES - XFixesSetPictureClipRegion(_ecore_x_disp, picture, x_origin, y_origin, region); -#endif + 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 index 56224f0..5396366 100644 --- a/src/lib/ecore_x/xlib/ecore_x_gc.c +++ b/src/lib/ecore_x/xlib/ecore_x_gc.c @@ -1,3 +1,9 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -7,15 +13,149 @@ * 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_new(Ecore_X_Drawable draw, + Ecore_X_GC_Value_Mask value_mask, + const unsigned int *value_list) { - XGCValues gcv; + 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; - if (!draw) draw = DefaultRootWindow(_ecore_x_disp); - return XCreateGC(_ecore_x_disp, draw, 0, &gcv); + 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); } /** @@ -23,7 +163,9 @@ ecore_x_gc_new(Ecore_X_Drawable draw) * @param gc The given graphics context. */ EAPI void -ecore_x_gc_del(Ecore_X_GC gc) +ecore_x_gc_free(Ecore_X_GC gc) { - XFreeGC(_ecore_x_disp, 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 index 399ca92..8d6ea1f 100644 --- a/src/lib/ecore_x/xlib/ecore_x_icccm.c +++ b/src/lib/ecore_x/xlib/ecore_x_icccm.c @@ -1,102 +1,122 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * 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) +ecore_x_icccm_state_set(Ecore_X_Window win, + Ecore_X_Window_State_Hint state) { - unsigned long c[2]; + unsigned long c[2]; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN) - c[0] = WithdrawnState; + c[0] = WithdrawnState; else if (state == ECORE_X_WINDOW_STATE_HINT_NORMAL) - c[0] = NormalState; + c[0] = NormalState; else if (state == ECORE_X_WINDOW_STATE_HINT_ICONIC) - c[0] = IconicState; + 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); + 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; + 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); + 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[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) +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); + 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) +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); + 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) +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); + 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) +ecore_x_icccm_move_resize_send(Ecore_X_Window win, + int x, + int y, + int w, + int h) { - XEvent ev; + XEvent ev; + LOGFN(__FILE__, __LINE__, __FUNCTION__); ev.type = ConfigureNotify; ev.xconfigure.display = _ecore_x_disp; ev.xconfigure.event = win; @@ -113,377 +133,443 @@ 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, - int 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, int is_urgent) + 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; + XWMHints *hints; hints = XAllocWMHints(); if (!hints) - return; + 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; + hints->initial_state = WithdrawnState; else if (initial_state == ECORE_X_WINDOW_STATE_HINT_NORMAL) - hints->initial_state = NormalState; + hints->initial_state = NormalState; else if (initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC) - hints->initial_state = IconicState; + hints->initial_state = IconicState; + if (icon_pixmap != 0) { - hints->icon_pixmap = icon_pixmap; - hints->flags |= IconPixmapHint; + hints->icon_pixmap = icon_pixmap; + hints->flags |= IconPixmapHint; } + if (icon_mask != 0) { - hints->icon_mask = icon_mask; - hints->flags |= IconMaskHint; + hints->icon_mask = icon_mask; + hints->flags |= IconMaskHint; } + if (icon_window != 0) { - hints->icon_window = icon_window; - hints->flags |= IconWindowHint; + hints->icon_window = icon_window; + hints->flags |= IconWindowHint; } + if (window_group != 0) { - hints->window_group = window_group; - hints->flags |= WindowGroupHint; + hints->window_group = window_group; + hints->flags |= WindowGroupHint; } + if (is_urgent) - hints->flags |= XUrgencyHint; + hints->flags |= XUrgencyHint; + XSetWMHints(_ecore_x_disp, win, hints); XFree(hints); } -EAPI int +EAPI Eina_Bool ecore_x_icccm_hints_get(Ecore_X_Window win, - int *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, int *is_urgent) + 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 = 1; + *accepts_focus = EINA_TRUE; + if (initial_state) - *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + *initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL; + if (icon_pixmap) - *icon_pixmap = 0; + *icon_pixmap = 0; + if (icon_mask) - *icon_mask = 0; + *icon_mask = 0; + if (icon_window) - *icon_window = 0; + *icon_window = 0; + if (window_group) - *window_group = 0; + *window_group = 0; + if (is_urgent) - *is_urgent = 0; + *is_urgent = EINA_FALSE; + hints = XGetWMHints(_ecore_x_disp, win); if (hints) { - if ((hints->flags & InputHint) && (accepts_focus)) - { - if (hints->input) - *accepts_focus = 1; - else - *accepts_focus = 0; - } - 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 = 1; - } - XFree(hints); - return 1; + 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 0; + + return EINA_FALSE; } EAPI void ecore_x_icccm_size_pos_hints_set(Ecore_X_Window win, - int 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) + 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; + XSizeHints hint; + long mask; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (!XGetWMNormalHints(_ecore_x_disp, win, &hint, &mask)) - { - memset(&hint, 0, sizeof(XSizeHints)); - } + memset(&hint, 0, sizeof(XSizeHints)); hint.flags = 0; if (request_pos) - { - hint.flags |= USPosition; - } + hint.flags |= USPosition; + if (gravity != ECORE_X_GRAVITY_NW) { - hint.flags |= PWinGravity; - hint.win_gravity = gravity; + 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; + 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; + 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; + 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; + 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; + 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 int +EAPI Eina_Bool ecore_x_icccm_size_pos_hints_get(Ecore_X_Window win, - int *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) + 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; + 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; + 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 0; + return EINA_FALSE; if ((hint.flags & USPosition) || ((hint.flags & PPosition))) { - if (request_pos) - *request_pos = 1; - } - else - { - if (request_pos) - *request_pos = 0; + 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 (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; + 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; + 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; + 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; + 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 (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; + *min_w = minw; + if (min_h) - *min_h = minh; + *min_h = minh; + if (max_w) - *max_w = maxw; + *max_w = maxw; + if (max_h) - *max_h = maxh; + *max_h = maxh; + if (base_w) - *base_w = basew; + *base_w = basew; + if (base_h) - *base_h = baseh; + *base_h = baseh; + if (step_x) - *step_x = stepx; + *step_x = stepx; + if (step_y) - *step_y = stepy; + *step_y = stepy; + if (min_aspect) - *min_aspect = mina; + *min_aspect = mina; + if (max_aspect) - *max_aspect = maxa; - return 1; + *max_aspect = maxa; + + return EINA_TRUE; } EAPI void -ecore_x_icccm_title_set(Ecore_X_Window win, const char *t) +ecore_x_icccm_title_set(Ecore_X_Window win, + const char *t) { - char *list[1]; - XTextProperty xprop; - int ret; + 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 + 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 + 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); + XSetWMName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); } - else + else if (XStringListToTextProperty(list, 1, &xprop) >= Success) { - if (XStringListToTextProperty(list, 1, &xprop) >= Success) - { - XSetWMName(_ecore_x_disp, win, &xprop); - if (xprop.value) XFree(xprop.value); - } + XSetWMName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); } + free(list[0]); } -EAPI char * +EAPI char * ecore_x_icccm_title_get(Ecore_X_Window win) { - XTextProperty xprop; + 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 */ + 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 - ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop, - &list, &num); -#endif - - 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; - } + 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 @@ -491,77 +577,82 @@ ecore_x_icccm_title_get(Ecore_X_Window win) */ EAPI void ecore_x_icccm_protocol_set(Ecore_X_Window win, - Ecore_X_WM_Protocol protocol, int on) + Ecore_X_WM_Protocol protocol, + Eina_Bool on) { - Atom *protos = NULL; - Atom proto; - int protos_count = 0; - int already_set = 0; - int i; + 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; + 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; + protos = NULL; + protos_count = 0; } for (i = 0; i < protos_count; i++) { - if (protos[i] == proto) - { - already_set = 1; - break; - } + 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); + 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; - } - } + 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: +leave: if (protos) XFree(protos); - } /** @@ -570,31 +661,35 @@ ecore_x_icccm_protocol_set(Ecore_X_Window win, * @param protocol The protocol to query * @return 1 if the protocol is set, else 0. */ -EAPI int -ecore_x_icccm_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol) +EAPI Eina_Bool +ecore_x_icccm_protocol_isset(Ecore_X_Window win, + Ecore_X_WM_Protocol protocol) { - Atom proto, *protos = NULL; - int i, ret = 0, protos_count = 0; + 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 0; + return EINA_FALSE; + LOGFN(__FILE__, __LINE__, __FUNCTION__); proto = _ecore_x_atoms_wm_protocols[protocol]; if (!XGetWMProtocols(_ecore_x_disp, win, &protos, &protos_count)) - return 0; + return EINA_FALSE; for (i = 0; i < protos_count; i++) - if (protos[i] == proto) - { - ret = 1; - break; - } + if (protos[i] == proto) + { + ret = EINA_TRUE; + break; + } - if (protos) XFree(protos); - return ret; + if (protos) + XFree(protos); + return ret; } /** @@ -602,17 +697,21 @@ ecore_x_icccm_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol) * @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) +ecore_x_icccm_name_class_set(Ecore_X_Window win, + const char *n, + const char *c) { - XClassHint *xch; + XClassHint *xch; xch = XAllocClassHint(); if (!xch) - return; + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); xch->res_name = (char *)n; xch->res_class = (char *)c; XSetClassHint(_ecore_x_disp, win, xch); @@ -624,30 +723,37 @@ ecore_x_icccm_name_class_set(Ecore_X_Window win, const char *n, const char *c) * @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) +ecore_x_icccm_name_class_get(Ecore_X_Window win, + char **n, + char **c) { - XClassHint xch; - - if (n) *n = NULL; - if (c) *c = NULL; + 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); + 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); } } @@ -655,28 +761,32 @@ ecore_x_icccm_name_class_get(Ecore_X_Window win, char **n, char **c) * 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 * +EAPI char * ecore_x_icccm_client_machine_get(Ecore_X_Window win) { - char *name; + 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) +ecore_x_icccm_command_set(Ecore_X_Window win, + int argc, + char **argv) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XSetCommand(_ecore_x_disp, win, argv, argc); } @@ -690,41 +800,55 @@ ecore_x_icccm_command_set(Ecore_X_Window win, int argc, char **argv) * @param argv Arguments. */ EAPI void -ecore_x_icccm_command_get(Ecore_X_Window win, int *argc, char ***argv) +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; + 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 (v) + XFreeStringList(v); + + return; } - if (argc) *argc = c; + 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(""); - } + (*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); } @@ -732,39 +856,41 @@ ecore_x_icccm_command_get(Ecore_X_Window win, int *argc, char ***argv) * 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) +ecore_x_icccm_icon_name_set(Ecore_X_Window win, + const char *t) { - char *list[1]; - XTextProperty xprop; - int ret; + 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 + XUTF8StringStyle, &xprop); +#else /* ifdef X_HAVE_UTF8_STRING */ list[0] = strdup(t); ret = XmbTextListToTextProperty(_ecore_x_disp, list, 1, - XStdICCTextStyle, &xprop); -#endif + XStdICCTextStyle, &xprop); +#endif /* ifdef X_HAVE_UTF8_STRING */ if (ret >= Success) { - XSetWMIconName(_ecore_x_disp, win, &xprop); - if (xprop.value) XFree(xprop.value); + XSetWMIconName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); } - else + else if (XStringListToTextProperty(list, 1, &xprop) >= Success) { - if (XStringListToTextProperty(list, 1, &xprop) >= Success) - { - XSetWMIconName(_ecore_x_disp, win, &xprop); - if (xprop.value) XFree(xprop.value); - } + XSetWMIconName(_ecore_x_disp, win, &xprop); + if (xprop.value) + XFree(xprop.value); } + free(list[0]); } @@ -772,60 +898,58 @@ ecore_x_icccm_icon_name_set(Ecore_X_Window win, const char *t) * 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 * +EAPI char * ecore_x_icccm_icon_name_get(Ecore_X_Window win) { - XTextProperty xprop; + 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 */ + 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 - ret = XmbTextPropertyToTextList(_ecore_x_disp, &xprop, - &list, &num); -#endif - - 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; - } + 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; } @@ -835,52 +959,60 @@ ecore_x_icccm_icon_name_get(Ecore_X_Window win) * @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) +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; + 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)) + 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; + 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; + 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); + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, 32, data, num); free(newset); } @@ -890,51 +1022,63 @@ ecore_x_icccm_colormap_window_set(Ecore_X_Window win, Ecore_X_Window subwin) * @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) +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; + 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; + ECORE_X_ATOM_WM_COLORMAP_WINDOWS, + XA_WINDOW, 32, &old_data, &num)) + return; - oldset = (Window *) old_data; + 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 (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); + if (old_data) + XFree(old_data); } /** @@ -943,18 +1087,21 @@ ecore_x_icccm_colormap_window_unset(Ecore_X_Window win, Ecore_X_Window subwin) * @param forwin the toplevel window */ EAPI void -ecore_x_icccm_transient_for_set(Ecore_X_Window win, Ecore_X_Window forwin) +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 The 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); } @@ -966,13 +1113,13 @@ ecore_x_icccm_transient_for_unset(Ecore_X_Window win) EAPI Ecore_X_Window ecore_x_icccm_transient_for_get(Ecore_X_Window win) { - Window forwin; + Window forwin; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (XGetTransientForHint(_ecore_x_disp, win, &forwin)) - return (Ecore_X_Window) forwin; + return (Ecore_X_Window)forwin; else - return 0; - + return 0; } /** @@ -981,10 +1128,12 @@ ecore_x_icccm_transient_for_get(Ecore_X_Window win) * @param role The role string */ EAPI void -ecore_x_icccm_window_role_set(Ecore_X_Window win, const char *role) +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); + (char *)role); } /** @@ -992,9 +1141,10 @@ ecore_x_icccm_window_role_set(Ecore_X_Window win, const char *role) * @param win The window * @return The window's role string. */ -EAPI char * +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); } @@ -1007,10 +1157,12 @@ ecore_x_icccm_window_role_get(Ecore_X_Window win) * 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) +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); + &l, 1); } /** @@ -1020,21 +1172,28 @@ 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) { - Ecore_X_Window l; + 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; + &l, 1) > 0) + return l; + return 0; } EAPI void -ecore_x_icccm_iconic_request_send(Ecore_X_Window win, Ecore_X_Window root) +ecore_x_icccm_iconic_request_send(Ecore_X_Window win, + Ecore_X_Window root) { XEvent xev; - if (!win) return; - if (!root) root = DefaultRootWindow(_ecore_x_disp); + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); xev.xclient.type = ClientMessage; xev.xclient.serial = 0; 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..f2b1d75 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_image.c @@ -0,0 +1,602 @@ +#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; + + ecore_x_sync(); + // 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 == MSBFirst) return EINA_TRUE; +#else + if (im->xim->bitmap_bit_order == LSBFirst) 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 index c009c7a..7812cc2 100644 --- a/src/lib/ecore_x/xlib/ecore_x_mwm.c +++ b/src/lib/ecore_x/xlib/ecore_x_mwm.c @@ -1,90 +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) +#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; + CARD32 flags; + CARD32 functions; + CARD32 decorations; + INT32 inputmode; + CARD32 status; } MWMHints; -EAPI int +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) + 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; - int ret; + unsigned char *p = NULL; + MWMHints *mwmhints = NULL; + int num; + Eina_Bool ret; - ret = 0; + 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 0; - mwmhints = (MWMHints *) p; + 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 = 1; - } - free(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, int borderless) +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; - - ecore_x_window_prop_property_set(win, - ECORE_X_ATOM_MOTIF_WM_HINTS, - ECORE_X_ATOM_MOTIF_WM_HINTS, - 32, (void *)data, 5); + + 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 index dacd7f8..5a23a1b 100644 --- a/src/lib/ecore_x/xlib/ecore_x_netwm.c +++ b/src/lib/ecore_x/xlib/ecore_x_netwm.c @@ -1,15 +1,18 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * _NET_WM... aka Extended Window Manager Hint (EWMH) functions. */ -#include "config.h" + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + #include "Ecore.h" -#include "Ecore_Data.h" #include "ecore_x_private.h" #include "Ecore_X.h" -#include "Ecore_X_Atoms.h" typedef struct _Ecore_X_Startup_Info Ecore_X_Startup_Info; @@ -17,60 +20,72 @@ struct _Ecore_X_Startup_Info { Ecore_X_Window win; - int init; + int init; - int buffer_size; - char *buffer; + int buffer_size; + char *buffer; - int length; + 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; + 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); +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 +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) + XChangeProperty(_ecore_x_disp, \ + win, \ + atom, \ + ECORE_X_ATOM_UTF8_STRING, \ + 8, \ + PropModeReplace, \ + (unsigned char *)string, \ + cnt) /* * Local variables */ -static Ecore_Hash *startup_info = NULL; +static Eina_Hash *startup_info = NULL; EAPI void ecore_x_netwm_init(void) { - startup_info = ecore_hash_new(ecore_direct_hash, ecore_direct_compare); - if (startup_info) - ecore_hash_free_value_cb_set(startup_info, _ecore_x_netwm_startup_info_free); + 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) - ecore_hash_destroy(startup_info); + eina_hash_free(startup_info); + startup_info = NULL; } @@ -78,85 +93,124 @@ ecore_x_netwm_shutdown(void) * WM identification */ EAPI void -ecore_x_netwm_wm_identify(Ecore_X_Window root, Ecore_X_Window check, - const char *wm_name) -{ - ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_SUPPORTING_WM_CHECK, &check, 1); - 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); +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_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) +ecore_x_netwm_supported_set(Ecore_X_Window root, + Ecore_X_Atom *supported, + int num) { - ecore_x_window_prop_atom_set(root, ECORE_X_ATOM_NET_SUPPORTED, supported, num); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + ecore_x_window_prop_atom_set(root, + ECORE_X_ATOM_NET_SUPPORTED, + supported, + num); } -EAPI int -ecore_x_netwm_supported_get(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) { - int num_ret; + int num_ret; + + if (num) + *num = 0; - if (num) *num = 0; - if (supported) *supported = NULL; + if (supported) + *supported = NULL; + LOGFN(__FILE__, __LINE__, __FUNCTION__); num_ret = ecore_x_window_prop_atom_list_get(root, ECORE_X_ATOM_NET_SUPPORTED, - supported); + supported); if (num_ret <= 0) - return 0; + return EINA_FALSE; - if (num) *num = num_ret; - return 1; + 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) +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); + &n_desks, 1); } EAPI void ecore_x_netwm_desk_roots_set(Ecore_X_Window root, - Ecore_X_Window *vroots, unsigned int n_desks) + Ecore_X_Window *vroots, + unsigned int n_desks) { - ecore_x_window_prop_window_set(root, ECORE_X_ATOM_NET_VIRTUAL_ROOTS, vroots, 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) + const char **names, + unsigned int n_desks) { - char ss[32], *buf; - const char *s; - unsigned int i; - int l, len; + 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; - buf = realloc(buf, len + l); - memcpy(buf + len, s, l); - len += l; + 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); @@ -165,63 +219,95 @@ ecore_x_netwm_desk_names_set(Ecore_X_Window root, } EAPI void -ecore_x_netwm_desk_size_set(Ecore_X_Window root, unsigned int width, - unsigned int height) +ecore_x_netwm_desk_size_set(Ecore_X_Window root, + unsigned int width, + unsigned int height) { - unsigned int size[2]; + 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); + 2); } EAPI void ecore_x_netwm_desk_viewports_set(Ecore_X_Window root, - unsigned int *origins, unsigned int n_desks) + 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); + 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) +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); + layout, 4); } EAPI void ecore_x_netwm_desk_workareas_set(Ecore_X_Window root, - unsigned int *areas, unsigned int n_desks) + 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); + 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) +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); + 1); } EAPI void -ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, int on) +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); + 1); } /* @@ -231,36 +317,46 @@ ecore_x_netwm_showing_desktop_set(Ecore_X_Window root, int on) /* Mapping order */ EAPI void ecore_x_netwm_client_list_set(Ecore_X_Window root, - Ecore_X_Window *p_clients, unsigned int n_clients) + 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); + 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) + 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); + p_clients, n_clients); } EAPI void -ecore_x_netwm_client_active_set(Ecore_X_Window root, Ecore_X_Window win) +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); + &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) +ecore_x_netwm_client_active_request(Ecore_X_Window root, + Ecore_X_Window win, + int type, + Ecore_X_Window current_win) { XEvent xev; - if (!root) root = DefaultRootWindow(_ecore_x_disp); - + 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; @@ -271,117 +367,156 @@ ecore_x_netwm_client_active_request(Ecore_X_Window root, Ecore_X_Window win, int xev.xclient.data.l[2] = current_win; xev.xclient.data.l[3] = 0; xev.xclient.data.l[4] = 0; - xev.xclient.data.l[5] = 0; - XSendEvent(_ecore_x_disp, root, False, - SubstructureRedirectMask | SubstructureNotifyMask, &xev); + XSendEvent(_ecore_x_disp, root, False, + SubstructureRedirectMask | SubstructureNotifyMask, &xev); } EAPI void -ecore_x_netwm_name_set(Ecore_X_Window win, const char *name) +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) +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); + *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) +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) +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); + *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) +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); + name); } EAPI int -ecore_x_netwm_visible_name_get(Ecore_X_Window win, char **name) +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); + *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) +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); + name); } EAPI int -ecore_x_netwm_icon_name_get(Ecore_X_Window win, char **name) +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); + *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) +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); + ECORE_X_ATOM_NET_WM_VISIBLE_ICON_NAME, + name); } EAPI int -ecore_x_netwm_visible_icon_name_get(Ecore_X_Window win, char **name) +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); + *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) +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 int -ecore_x_netwm_desktop_get(Ecore_X_Window win, unsigned int *desk) +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); + &tmp, 1); - if (desk) *desk = tmp; - return ret == 1 ? 1 : 0; + 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) +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; @@ -392,32 +527,57 @@ ecore_x_netwm_strut_set(Ecore_X_Window win, int left, int right, /* * _NET_WM_STRUT is deprecated */ -EAPI int -ecore_x_netwm_strut_get(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) { int ret = 0; unsigned int strut[4]; - ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT, 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 0; + return EINA_FALSE; - if (left) *left = strut[0]; - if (right) *right = strut[1]; - if (top) *top = strut[2]; - if (bottom) *bottom = strut[3]; - return 1; + 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) +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; @@ -430,57 +590,157 @@ ecore_x_netwm_strut_partial_set(Ecore_X_Window win, int left, int right, 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 int -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) + 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]; - ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_STRUT_PARTIAL, 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 0; + 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 1; + 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 int -ecore_x_netwm_icons_get(Ecore_X_Window win, Ecore_X_Icon **icon, int *num) +EAPI void +ecore_x_netwm_icons_set(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; + 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); +} - if (num) *num = 0; - if (icon) *icon = NULL; +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); + &data); if (num_ret <= 0) - return 0; - if (!data) return 0; + return EINA_FALSE; + + if (!data) + return EINA_FALSE; + if (num_ret < 2) { - free(data); - return 0; + free(data); + return EINA_FALSE; } /* Check how many icons there are */ @@ -488,161 +748,201 @@ ecore_x_netwm_icons_get(Ecore_X_Window win, Ecore_X_Icon **icon, int *num) p = data; while (p) { - len = p[0] * p[1]; - p += (len + 2); - if ((p - data) > num_ret) - { - free(data); - return 0; - } - icons++; - - if ((p - data) == num_ret) - p = NULL; + 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 (num) + *num = icons; /* If the user doesn't want the icons, return */ if (!icon) { - free(data); - return 1; + free(data); + return EINA_TRUE; } /* Allocate memory */ *icon = malloc(icons * sizeof(Ecore_X_Icon)); if (!(*icon)) { - free(data); - return 0; + 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 0; - } - - 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); + 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 1; + return EINA_TRUE; } EAPI void -ecore_x_netwm_icon_geometry_set(Ecore_X_Window win, int x, int y, int width, int height) +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); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, + geometry, + 4); } -EAPI int -ecore_x_netwm_icon_geometry_get(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) { int ret; unsigned int geometry[4]; - ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_ICON_GEOMETRY, 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 0; + return EINA_FALSE; - if (x) *x = geometry[0]; - if (y) *y = geometry[1]; - if (width) *width = geometry[2]; - if (height) *height = geometry[3]; - return 1; + 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) +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); + &tmp, 1); } -EAPI int -ecore_x_netwm_pid_get(Ecore_X_Window win, int *pid) +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 ? 1 : 0; + &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); + NULL, 0); } -EAPI int +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 ? 1 : 0; + NULL, 0); + return ret == 0 ? EINA_TRUE : EINA_FALSE; } EAPI void -ecore_x_netwm_user_time_set(Ecore_X_Window win, unsigned int time) +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, - &time, 1); + &tim, 1); } -EAPI int -ecore_x_netwm_user_time_get(Ecore_X_Window win, unsigned int *time) +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 (time) *time = tmp; - return ret == 1 ? 1 : 0; + &tmp, 1); + if (tim) + *tim = tmp; + + return ret == 1 ? EINA_TRUE : EINA_FALSE; } Ecore_X_Window_State @@ -679,51 +979,67 @@ _ecore_x_netwm_state_get(Ecore_X_Atom a) static Ecore_X_Atom _ecore_x_netwm_state_atom_get(Ecore_X_Window_State s) { - switch(s) + switch (s) { case ECORE_X_WINDOW_STATE_MODAL: - return ECORE_X_ATOM_NET_WM_STATE_MODAL; + return ECORE_X_ATOM_NET_WM_STATE_MODAL; + case ECORE_X_WINDOW_STATE_STICKY: - return ECORE_X_ATOM_NET_WM_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; + 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; + return ECORE_X_ATOM_NET_WM_STATE_MAXIMIZED_HORZ; + case ECORE_X_WINDOW_STATE_SHADED: - return ECORE_X_ATOM_NET_WM_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; + 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; + return ECORE_X_ATOM_NET_WM_STATE_SKIP_PAGER; + case ECORE_X_WINDOW_STATE_HIDDEN: - return ECORE_X_ATOM_NET_WM_STATE_HIDDEN; + return ECORE_X_ATOM_NET_WM_STATE_HIDDEN; + case ECORE_X_WINDOW_STATE_FULLSCREEN: - return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; + return ECORE_X_ATOM_NET_WM_STATE_FULLSCREEN; + case ECORE_X_WINDOW_STATE_ABOVE: - return ECORE_X_ATOM_NET_WM_STATE_ABOVE; + return ECORE_X_ATOM_NET_WM_STATE_ABOVE; + case ECORE_X_WINDOW_STATE_BELOW: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_STATE_DEMANDS_ATTENTION; + default: - return 0; + return 0; } } EAPI void -ecore_x_netwm_window_state_set(Ecore_X_Window win, Ecore_X_Window_State *state, unsigned int num) +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; + 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; + ecore_x_window_prop_property_del(win, ECORE_X_ATOM_NET_WM_STATE); + return; } set = malloc(num * sizeof(Ecore_X_Atom)); - if (!set) return; + if (!set) + return; for (i = 0; i < num; i++) set[i] = _ecore_x_netwm_state_atom_get(state[i]); @@ -733,32 +1049,39 @@ ecore_x_netwm_window_state_set(Ecore_X_Window win, Ecore_X_Window_State *state, free(set); } -EAPI int -ecore_x_netwm_window_state_get(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) { - int num_ret, i; - Ecore_X_Atom *atoms; + int num_ret, i; + Ecore_X_Atom *atoms; - if (num) *num = 0; - if (state) *state = NULL; + 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); + &atoms); if (num_ret <= 0) - return 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]); + *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; + if (num) + *num = num_ret; } free(atoms); - return 1; + return EINA_TRUE; } static Ecore_X_Window_Type @@ -780,6 +1103,18 @@ _ecore_x_netwm_window_type_type_get(Ecore_X_Atom atom) 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; } @@ -790,23 +1125,49 @@ _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; + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DESKTOP; + case ECORE_X_WINDOW_TYPE_DOCK: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_TOOLBAR; + case ECORE_X_WINDOW_TYPE_MENU: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_UTILITY; + case ECORE_X_WINDOW_TYPE_SPLASH: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_WINDOW_TYPE_DIALOG; + case ECORE_X_WINDOW_TYPE_NORMAL: - return ECORE_X_ATOM_NET_WM_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; + return 0; } } @@ -815,58 +1176,77 @@ _ecore_x_netwm_window_type_atom_get(Ecore_X_Window_Type type) * , 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_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); + &atom, 1); } /* FIXME: Maybe return 0 on some conditions? */ -EAPI int -ecore_x_netwm_window_type_get(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) { - int num; - Ecore_X_Atom *atoms = NULL; + int num; + Ecore_X_Atom *atoms = NULL; - if (type) *type = ECORE_X_WINDOW_TYPE_NORMAL; + 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); + 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 1; - return 0; + 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) +ecore_x_netwm_window_types_get(Ecore_X_Window win, + Ecore_X_Window_Type **types) { - int num, i; - Ecore_X_Atom *atoms = NULL; + int num, i; + Ecore_X_Atom *atoms = NULL; Ecore_X_Window_Type *atoms2 = NULL; - - if (types) *types = 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); + ECORE_X_ATOM_NET_WM_WINDOW_TYPE, + &atoms); if ((num <= 0) || (!atoms)) { - if (atoms) free(atoms); - return 0; + if (atoms) + free(atoms); + + return 0; } + atoms2 = malloc(num * sizeof(Ecore_X_Window_Type)); - if (!atoms2) return 0; + 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); + if (types) + *types = atoms2; + else + free(atoms2); + return num; } @@ -876,39 +1256,58 @@ _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; + return ECORE_X_ATOM_NET_WM_ACTION_MOVE; + case ECORE_X_ACTION_RESIZE: - return ECORE_X_ATOM_NET_WM_ACTION_RESIZE; + return ECORE_X_ATOM_NET_WM_ACTION_RESIZE; + case ECORE_X_ACTION_MINIMIZE: - return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; + return ECORE_X_ATOM_NET_WM_ACTION_MINIMIZE; + case ECORE_X_ACTION_SHADE: - return ECORE_X_ATOM_NET_WM_ACTION_SHADE; + return ECORE_X_ATOM_NET_WM_ACTION_SHADE; + case ECORE_X_ACTION_STICK: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_ACTION_MAXIMIZE_HORZ; + case ECORE_X_ACTION_MAXIMIZE_VERT: - return ECORE_X_ATOM_NET_WM_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; + return ECORE_X_ATOM_NET_WM_ACTION_FULLSCREEN; + case ECORE_X_ACTION_CHANGE_DESKTOP: - return ECORE_X_ATOM_NET_WM_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; + 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; + return 0; } } /* FIXME: Get complete list */ -EAPI int -ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, Ecore_X_Action action) +EAPI Eina_Bool +ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, + Ecore_X_Action action) { - int num, i, ret = 0; - Ecore_X_Atom *atoms, atom; + 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); + &atoms); if (num <= 0) return ret; @@ -916,11 +1315,11 @@ ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, Ecore_X_Action action) for (i = 0; i < num; ++i) { - if (atom == atoms[i]) - { - ret = 1; - break; - } + if (atom == atoms[i]) + { + ret = 1; + break; + } } free(atoms); @@ -929,115 +1328,169 @@ ecore_x_netwm_allowed_action_isset(Ecore_X_Window win, Ecore_X_Action action) /* 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_netwm_allowed_action_set(Ecore_X_Window win, + Ecore_X_Action *action, + unsigned int num) { - Ecore_X_Atom *set; - unsigned int i; + 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; + 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; + 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); + ecore_x_window_prop_atom_set(win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + set, + num); free(set); } -EAPI int -ecore_x_netwm_allowed_action_get(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) { - int num_ret, i; - Ecore_X_Atom *atoms; + int num_ret, i; + Ecore_X_Atom *atoms; - if (num) *num = 0; - if (action) *action = NULL; + 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); + num_ret = ecore_x_window_prop_atom_list_get( + win, + ECORE_X_ATOM_NET_WM_ALLOWED_ACTIONS, + &atoms); if (num_ret <= 0) - return 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]); + *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; + if (num) + *num = num_ret; } free(atoms); - return 1; + return EINA_TRUE; } EAPI void -ecore_x_netwm_opacity_set(Ecore_X_Window win, unsigned int opacity) +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); + &opacity, 1); } -EAPI int -ecore_x_netwm_opacity_get(Ecore_X_Window win, unsigned int *opacity) +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 ? 1 : 0; + &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) +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); + ecore_x_window_prop_card32_set(win, + ECORE_X_ATOM_NET_FRAME_EXTENTS, + frames, + 4); } -EAPI int -ecore_x_netwm_frame_size_get(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) { int ret = 0; unsigned int frames[4]; - ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_FRAME_EXTENTS, 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 0; + return EINA_FALSE; - if (fl) *fl = frames[0]; - if (fr) *fr = frames[1]; - if (ft) *ft = frames[2]; - if (fb) *fb = frames[3]; - return 1; + if (fl) + *fl = frames[0]; + + if (fr) + *fr = frames[1]; + + if (ft) + *ft = frames[2]; + + if (fb) + *fb = frames[3]; + + return EINA_TRUE; } -EAPI int -ecore_x_netwm_sync_counter_get(Ecore_X_Window win, Ecore_X_Sync_Counter *counter) +EAPI Eina_Bool +ecore_x_netwm_sync_counter_get(Ecore_X_Window win, + Ecore_X_Sync_Counter *counter) { - int ret; + int ret; unsigned int tmp; - ret = ecore_x_window_prop_card32_get(win, ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER, - &tmp, 1); + 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; - if (counter) *counter = tmp; - return ret == 1 ? 1 : 0; + return ret == 1 ? EINA_TRUE : EINA_FALSE; } EAPI void @@ -1045,31 +1498,35 @@ ecore_x_netwm_ping_send(Ecore_X_Window win) { XEvent xev; - if (!win) return; + 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] = CurrentTime; + 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; - xev.xclient.data.l[5] = 0; XSendEvent(_ecore_x_disp, win, False, NoEventMask, &xev); } EAPI void -ecore_x_netwm_sync_request_send(Ecore_X_Window win, unsigned int serial) +ecore_x_netwm_sync_request_send(Ecore_X_Window win, + unsigned int serial) { XSyncValue value; XEvent xev; - if (!win) return; + if (!win) + return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); XSyncIntToValue(&value, (int)serial); xev.xclient.type = ClientMessage; @@ -1078,7 +1535,7 @@ ecore_x_netwm_sync_request_send(Ecore_X_Window win, unsigned int serial) 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] = CurrentTime; + 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; @@ -1087,13 +1544,20 @@ 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, int set) +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; - if (!root) root = DefaultRootWindow(_ecore_x_disp); + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); xev.xclient.type = ClientMessage; xev.xclient.serial = 0; @@ -1111,16 +1575,22 @@ ecore_x_netwm_state_request_send(Ecore_X_Window win, Ecore_X_Window root, xev.xclient.data.l[4] = 0; XSendEvent(_ecore_x_disp, root, False, - SubstructureNotifyMask | SubstructureRedirectMask, &xev); + SubstructureNotifyMask | SubstructureRedirectMask, &xev); } EAPI void -ecore_x_netwm_desktop_request_send(Ecore_X_Window win, Ecore_X_Window root, unsigned int desktop) +ecore_x_netwm_desktop_request_send(Ecore_X_Window win, + Ecore_X_Window root, + unsigned int desktop) { XEvent xev; - if (!win) return; - if (!root) root = DefaultRootWindow(_ecore_x_disp); + if (!win) + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (!root) + root = DefaultRootWindow(_ecore_x_disp); xev.xclient.type = ClientMessage; xev.xclient.serial = 0; @@ -1132,83 +1602,121 @@ ecore_x_netwm_desktop_request_send(Ecore_X_Window win, Ecore_X_Window root, unsi xev.xclient.data.l[0] = desktop; XSendEvent(_ecore_x_disp, root, False, - SubstructureNotifyMask | SubstructureRedirectMask, &xev); + 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, char *data) +_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; - if (!startup_info) return 0; - info = ecore_hash_get(startup_info, (void *)win); + info = eina_hash_find(startup_info, (void *)win); if (info) { - printf("Already got info for win: 0x%x\n", win); - _ecore_x_netwm_startup_info_free(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; + 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; + _ecore_x_netwm_startup_info_free(info); + return 0; } + memcpy(info->buffer, data, 20); info->length += 20; info->buffer[info->length] = 0; - ecore_hash_set(startup_info, (void *)info->win, info); + 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); - } -#else - win = 0; - data = NULL; -#endif + /* 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, char *data) +_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 = ecore_hash_get(startup_info, (void *)win); - if (!info) return 0; + 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) - { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; - } + 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); - } -#else - win = 0; - data = NULL; -#endif + /* We have a '\0' in there, the message is done */ + _ecore_x_netwm_startup_info_process(info); + +#endif /* if 0 */ return 1; } @@ -1216,41 +1724,44 @@ _ecore_x_netwm_startup_info(Ecore_X_Window win, char *data) * 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) +_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)); + 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) +_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; + 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); + 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'; - } + str = malloc(num_ret + 1); + if (str) + { + memcpy(str, prop_ret, num_ret); + str[num_ret] = '\0'; + } } + if (prop_ret) - XFree(prop_ret); + XFree(prop_ret); return str; } @@ -1263,71 +1774,73 @@ static int _ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info) { Ecore_X_Event_Startup_Sequence *e; - int event; - char *p; + int event; + char *p; p = strchr(info->buffer, ':'); if (!p) { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; + 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; + 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; - } + event = ECORE_X_EVENT_STARTUP_SEQUENCE_CHANGE; else if (!strcmp(info->buffer, "remove")) event = ECORE_X_EVENT_STARTUP_SEQUENCE_REMOVE; else { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; + 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)) { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); - return 0; + 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) - { - ecore_hash_remove(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); + 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) { - ecore_hash_remove(startup_info, (void *)info->win); - _ecore_x_netwm_startup_info_free(info); + 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; + /* Discard buffer */ + info->length = 0; + info->buffer[0] = 0; } + return 1; } @@ -1335,150 +1848,161 @@ _ecore_x_netwm_startup_info_process(Ecore_X_Startup_Info *info) * Parse startup info */ static int -_ecore_x_netwm_startup_info_parse(Ecore_X_Startup_Info *info, char *data) +_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 - { - printf("Ecore X Sequence, Unknown: %s=%s\n", key, value); - } + 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; + if (!info->id) + return 0; + return 1; } -#endif + +#endif /* if 0 */ /* * Free startup info struct @@ -1489,32 +2013,71 @@ _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); + 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 int +EAPI Eina_Bool ecore_x_screen_is_composited(int screen) { - Ecore_X_Window win; - Ecore_X_Atom atom; - char buf[32]; + 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); - snprintf(buf, sizeof(buf), "_NET_WM_CM_S%d", screen); - atom = XInternAtom(_ecore_x_disp, buf, True); - if (atom == None) return 0; + if (atom == None) + return EINA_FALSE; win = XGetSelectionOwner(_ecore_x_disp, atom); - return win != None; + 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 index 9911200..7b13615 100644 --- a/src/lib/ecore_x/xlib/ecore_x_pixmap.c +++ b/src/lib/ecore_x/xlib/ecore_x_pixmap.c @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -21,10 +25,18 @@ * @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_new(Ecore_X_Window win, + int w, + int h, + int dep) { - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); - if (dep == 0) dep = DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)); + 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); } @@ -38,8 +50,9 @@ ecore_x_pixmap_new(Ecore_X_Window win, int w, int h, int dep) * @ingroup Ecore_X_Pixmap_Group */ EAPI void -ecore_x_pixmap_del(Ecore_X_Pixmap pmap) +ecore_x_pixmap_free(Ecore_X_Pixmap pmap) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XFreePixmap(_ecore_x_disp, pmap); } @@ -58,10 +71,17 @@ ecore_x_pixmap_del(Ecore_X_Pixmap pmap) * @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) +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); } @@ -75,10 +95,15 @@ ecore_x_pixmap_paste(Ecore_X_Pixmap pmap, Ecore_X_Drawable dest, * @ingroup Ecore_X_Pixmap_Group */ EAPI void -ecore_x_pixmap_geometry_get(Ecore_X_Pixmap pmap, int *x, int *y, int *w, int *h) +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); + ecore_x_drawable_geometry_get(pmap, x, y, w, h); } /** @@ -90,6 +115,7 @@ 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) { + 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 index 9fcb649..f962ffb 100644 --- a/src/lib/ecore_x/xlib/ecore_x_private.h +++ b/src/lib/ecore_x/xlib/ecore_x_private.h @@ -1,14 +1,11 @@ #ifndef _ECORE_X_PRIVATE_H #define _ECORE_X_PRIVATE_H -#include "config.h" - #include #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 -#endif +#endif /* ifndef MAXHOSTNAMELEN */ -#define XK_MISCELLANY 1 #include #include #include @@ -21,59 +18,102 @@ #include #ifdef ECORE_XCURSOR #include -#endif +#endif /* ifdef ECORE_XCURSOR */ #ifdef ECORE_XPRINT #include -#endif +#endif /* ifdef ECORE_XPRINT */ #ifdef ECORE_XINERAMA #include -#endif +#endif /* ifdef ECORE_XINERAMA */ #ifdef ECORE_XRANDR #include -#endif +#endif /* ifdef ECORE_XRANDR */ #ifdef ECORE_XSS #include -#endif +#endif /* ifdef ECORE_XSS */ #ifdef ECORE_XRENDER #include -#endif +#endif /* ifdef ECORE_XRENDER */ #ifdef ECORE_XFIXES #include -#endif +#endif /* ifdef ECORE_XFIXES */ #ifdef ECORE_XCOMPOSITE #include -#endif +#endif /* ifdef ECORE_XCOMPOSITE */ #ifdef ECORE_XDAMAGE #include -#endif +#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__) -/* FIXME: this is for simulation only */ -#include "Ecore_Txt.h" +#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; + 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; - int (*convert)(char *target, void *data, int size, - void **data_ret, int *size_ret); + 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; }; @@ -81,16 +121,16 @@ 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); + char *target; + void *(*parse)(const char *target, void *data, int size, int format); Ecore_X_Selection_Parser *next; }; -typedef struct _Ecore_X_DND_Source +typedef struct _Ecore_X_DND_Source { - int version; + int version; Ecore_X_Window win, dest; - + enum { ECORE_X_DND_SOURCE_IDLE, ECORE_X_DND_SOURCE_DRAGGING, @@ -98,60 +138,71 @@ typedef struct _Ecore_X_DND_Source ECORE_X_DND_SOURCE_CONVERTING } state; - struct { - short x, y; + struct + { + short x, y; unsigned short width, height; } rectangle; - Time time; + 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; + int will_accept; + int suppress; + + int await_status; } Ecore_X_DND_Source; -typedef struct _Ecore_X_DND_Target +typedef struct _Ecore_X_DND_Target { - int version; + int version; Ecore_X_Window win, source; - + enum { ECORE_X_DND_TARGET_IDLE, ECORE_X_DND_TARGET_ENTERED } state; - struct { + struct + { int x, y; } pos; - - Time time; + + Time time; Ecore_X_Atom action, accepted_action; - - int will_accept; + + 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 int _ecore_x_xcursor; +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 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 int (*_ecore_window_grab_replay_func) (void *data, int event_type, void *event); -extern void *_ecore_window_grab_replay_data; +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); @@ -161,7 +212,7 @@ 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_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); @@ -186,53 +237,143 @@ 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); -#endif +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 +#endif /* ifdef ECORE_XFIXES */ #ifdef ECORE_XDAMAGE -void _ecore_x_event_handle_damage_notify(XEvent *xevent); -#endif +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_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); -int _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); -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_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); +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_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); +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 */ -#endif +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 index 3509957..58a2830 100644 --- a/src/lib/ecore_x/xlib/ecore_x_randr.c +++ b/src/lib/ecore_x/xlib/ecore_x_randr.c @@ -1,264 +1,103 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab: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" -EAPI int -ecore_x_randr_query() -{ +static Eina_Bool _randr_available = EINA_FALSE; #ifdef ECORE_XRANDR - int randr_base = 0; - int randr_err_base = 0; +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) - if (XRRQueryExtension(_ecore_x_disp, &randr_base, &randr_err_base)) - return 1; - else - return 0; -#else - return 0; -#endif -} +#define RANDR_VALIDATE_ROOT(screen, \ + root) ((screen = \ + XRRRootToScreen(_ecore_x_disp, \ + root)) != -1) -EAPI int -ecore_x_randr_events_select(Ecore_X_Window win, int on) -{ -#ifdef ECORE_XRANDR - if (on) - XRRSelectInput(_ecore_x_disp, win, RRScreenChangeNotifyMask); - else - XRRSelectInput(_ecore_x_disp, win, 0); +#define Ecore_X_Randr_Unset -1 - return 1; -#else - return 0; -#endif -} +XRRScreenResources *(*_ecore_x_randr_get_screen_resources)(Display * dpy, + Window window); -EAPI Ecore_X_Randr_Rotation -ecore_x_randr_screen_rotations_get(Ecore_X_Window root) -{ -#ifdef ECORE_XRANDR - Rotation rot, crot; - - rot = XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &crot); - return rot; -#else - return 0; -#endif -} +#endif /* ifdef ECORE_XRANDR */ -EAPI Ecore_X_Randr_Rotation -ecore_x_randr_screen_rotation_get(Ecore_X_Window root) +void +_ecore_x_randr_init(void) { #ifdef ECORE_XRANDR - Rotation rot, crot = 0; - - rot = XRRRotations(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &crot); - return crot; -#else - return 0; -#endif -} - -EAPI void -ecore_x_randr_screen_rotation_set(Ecore_X_Window root, Ecore_X_Randr_Rotation rot) -{ -#ifdef ECORE_XRANDR - XRRScreenConfiguration *xrrcfg; - SizeID sizeid; - Rotation crot; - - xrrcfg = XRRGetScreenInfo(_ecore_x_disp, root); - if (!xrrcfg) return; - sizeid = XRRConfigCurrentConfiguration(xrrcfg, &crot); - XRRSetScreenConfig(_ecore_x_disp, xrrcfg, root, sizeid, rot, CurrentTime); - XRRFreeScreenConfigInfo(xrrcfg); -#endif -} - -EAPI Ecore_X_Screen_Size * -ecore_x_randr_screen_sizes_get(Ecore_X_Window root, int *num) -{ -#ifdef ECORE_XRANDR - Ecore_X_Screen_Size *ret; - XRRScreenSize *sizes; - int i, n; + _randr_major = 1; + _randr_minor = 3; + _randr_version = 0; - if (num) *num = 0; - - /* we don't have to free sizes, no idea why not */ - sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); - ret = calloc(n, sizeof(Ecore_X_Screen_Size)); - if (!ret) return NULL; - - if (num) *num = n; - for (i = 0; i < n; i++) + _ecore_x_randr_get_screen_resources = NULL; + if (XRRQueryVersion(_ecore_x_disp, &_randr_major, &_randr_minor)) { - ret[i].width = sizes[i].width; - ret[i].height = sizes[i].height; - } - return ret; -#else - if (num) *num = 0; - return NULL; -#endif -} - -EAPI Ecore_X_Screen_Size -ecore_x_randr_current_screen_size_get(Ecore_X_Window root) -{ - Ecore_X_Screen_Size ret = { -1, -1 }; -#ifdef ECORE_XRANDR - XRRScreenSize *sizes; - XRRScreenConfiguration *sc; - SizeID size_index; - Rotation rotation; - int n; + _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; - sc = XRRGetScreenInfo(_ecore_x_disp, root); - if (!sc) - { - printf("ERROR: Couldn't get screen information for %d\n", root); - return ret; + _randr_available = EINA_TRUE; } - size_index = XRRConfigCurrentConfiguration(sc, &rotation); - - sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); - if (size_index < n) - { - ret.width = sizes[size_index].width; - ret.height = sizes[size_index].height; - } - XRRFreeScreenConfigInfo(sc); -#endif - return ret; -} - -EAPI int -ecore_x_randr_screen_size_set(Ecore_X_Window root, Ecore_X_Screen_Size size) -{ -#ifdef ECORE_XRANDR - XRRScreenConfiguration *sc; - XRRScreenSize *sizes; - int i, n, size_index = -1; + else + _randr_available = EINA_FALSE; - sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); - for (i = 0; i < n; i++) - { - if ((sizes[i].width == size.width) && (sizes[i].height == size.height)) - { - size_index = i; - break; - } - } - if (size_index == -1) return 0; - - sc = XRRGetScreenInfo(_ecore_x_disp, root); - if (XRRSetScreenConfig(_ecore_x_disp, sc, - root, size_index, - RR_Rotate_0, CurrentTime)) - { - printf("ERROR: Can't set new screen size!\n"); - XRRFreeScreenConfigInfo(sc); - return 0; - } - XRRFreeScreenConfigInfo(sc); - return 1; #else - return 0; + _randr_available = EINA_FALSE; #endif } -EAPI Ecore_X_Screen_Refresh_Rate -ecore_x_randr_current_screen_refresh_rate_get(Ecore_X_Window root) +/* + * @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) { - Ecore_X_Screen_Refresh_Rate ret = { -1 }; -#ifdef ECORE_XRANDR - XRRScreenConfiguration *sc; - - sc = XRRGetScreenInfo(_ecore_x_disp, root); - if (!sc) - { - printf("ERROR: Couldn't get screen information for %d\n", root); - return ret; - } - ret.rate = XRRConfigCurrentRate(sc); - XRRFreeScreenConfigInfo(sc); -#endif - return ret; + return _randr_available; } -EAPI Ecore_X_Screen_Refresh_Rate * -ecore_x_randr_screen_refresh_rates_get(Ecore_X_Window root, int size_id, int *num) +/* + * @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 - Ecore_X_Screen_Refresh_Rate *ret = NULL; - XRRScreenConfiguration *sc; - short *rates; - int i, n; - - if (num) *num = 0; - - sc = XRRGetScreenInfo(_ecore_x_disp, root); - if (!sc) + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (_randr_available) { - printf("ERROR: Couldn't get screen information for %d\n", root); - return ret; + return _randr_version; } - - rates = XRRRates(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), size_id, &n); - ret = calloc(n, sizeof(Ecore_X_Screen_Refresh_Rate)); - if (!ret) - { - XRRFreeScreenConfigInfo(sc); - return NULL; - } - - if (num) *num = n; - for (i = 0; i < n; i++) + else { - ret[i].rate = rates[i]; + return Ecore_X_Randr_Unset; } - XRRFreeScreenConfigInfo(sc); - return ret; #else - if (num) *num = 0; - return NULL; + return -1; #endif } -EAPI int -ecore_x_randr_screen_refresh_rate_set(Ecore_X_Window root, Ecore_X_Screen_Size size, Ecore_X_Screen_Refresh_Rate rate) +Eina_Bool +_ecore_x_randr_root_validate(Ecore_X_Window root) { #ifdef ECORE_XRANDR - XRRScreenConfiguration *sc; - XRRScreenSize *sizes; - int i, n, size_index = -1; + Ecore_X_Randr_Screen scr = -1; + if (root && RANDR_VALIDATE_ROOT(scr, root)) + return EINA_TRUE; + else + return EINA_FALSE; - sizes = XRRSizes(_ecore_x_disp, XRRRootToScreen(_ecore_x_disp, root), &n); - for (i = 0; i < n; i++) - { - if ((sizes[i].width == size.width) && (sizes[i].height == size.height)) - { - size_index = i; - break; - } - } - if (size_index == -1) return 0; - - sc = XRRGetScreenInfo(_ecore_x_disp, root); - if (XRRSetScreenConfigAndRate(_ecore_x_disp, sc, - root, size_index, - RR_Rotate_0, rate.rate, CurrentTime)) - { - printf("ERROR: Can't set new screen size and refresh rate!\n"); - XRRFreeScreenConfigInfo(sc); - return 0; - } - XRRFreeScreenConfigInfo(sc); - return 1; #else - return 1; + 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..97f1d0c --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_randr_12.c @@ -0,0 +1,2412 @@ +/* + * 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 (root && + (res = _ecore_x_randr_get_screen_resources (_ecore_x_disp, root))) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Crtc) * res->ncrtc))) + { + int i = 0; + + if (num) *num = res->ncrtc; + + for (i = 0; i < res->ncrtc; i++) + ret[i] = res->crtcs[i]; + } + + 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 (root && + (res = _ecore_x_randr_get_screen_resources(_ecore_x_disp, root))) + { + if ((ret = malloc(sizeof(Ecore_X_Randr_Output) * res->noutput))) + { + int i = 0; + + if (num) *num = res->noutput; + + for (i = 0; i < res->noutput; i++) + ret[i] = res->outputs[i]; + } + + 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))) + { + int i = 0; + + if (num) *num = crtc_info->noutput; + + for (i = 0; i < crtc_info->noutput; i++) + ret[i] = crtc_info->outputs[i]; + } + + 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))) + { + int i = 0; + + if (num) *num = crtc_info->npossible; + + for (i = 0; i < crtc_info->npossible; i++) + ret[i] = crtc_info->possible[i]; + } + + 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))) + { + int i = 0; + + if (num) *num = output_info->nmode; + if (npreferred) *npreferred = output_info->npreferred; + + for (i = 0; i < output_info->nmode; i++) + modes[i] = output_info->modes[i]; + } + } + + 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 index 6559cad..3688a44 100644 --- a/src/lib/ecore_x/xlib/ecore_x_screensaver.c +++ b/src/lib/ecore_x/xlib/ecore_x_screensaver.c @@ -1,9 +1,11 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * Screensaver code */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -11,23 +13,28 @@ static int _screensaver_available = -1; -EAPI int +EAPI Eina_Bool ecore_x_screensaver_event_available_get(void) { - if (_screensaver_available >= 0) return _screensaver_available; + 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)) + if (XScreenSaverQueryVersion(_ecore_x_disp, &_screensaver_major, + &_screensaver_minor)) _screensaver_available = 1; else _screensaver_available = 0; -#else + +#else /* ifdef ECORE_XSS */ _screensaver_available = 0; -#endif +#endif /* ifdef ECORE_XSS */ return _screensaver_available; } @@ -38,21 +45,32 @@ ecore_x_screensaver_idle_time_get(void) XScreenSaverInfo *xss; int idle; + LOGFN(__FILE__, __LINE__, __FUNCTION__); xss = XScreenSaverAllocInfo(); - XScreenSaverQueryInfo(_ecore_x_disp, RootWindow(_ecore_x_disp, DefaultScreen(_ecore_x_disp)), xss); + XScreenSaverQueryInfo(_ecore_x_disp, + RootWindow(_ecore_x_disp, DefaultScreen( + _ecore_x_disp)), xss); idle = xss->idle / 1000; XFree(xss); return idle; -#endif - +#else return 0; +#endif /* ifdef ECORE_XSS */ } EAPI void -ecore_x_screensaver_set(int timeout, int interval, int prefer_blanking, int allow_exposures) +ecore_x_screensaver_set(int timeout, + int interval, + int prefer_blanking, + int allow_exposures) { - XSetScreenSaver(_ecore_x_disp, timeout, interval, prefer_blanking, allow_exposures); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + XSetScreenSaver(_ecore_x_disp, + timeout, + interval, + prefer_blanking, + allow_exposures); } EAPI void @@ -60,6 +78,7 @@ 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); } @@ -69,6 +88,7 @@ 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; } @@ -78,6 +98,7 @@ 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); } @@ -87,6 +108,7 @@ 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; } @@ -96,6 +118,7 @@ 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); } @@ -105,6 +128,7 @@ 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; } @@ -114,6 +138,7 @@ 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); } @@ -123,22 +148,57 @@ 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(int on) +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); + XScreenSaverSelectInput(_ecore_x_disp, root, + ScreenSaverNotifyMask | ScreenSaverCycle); else XScreenSaverSelectInput(_ecore_x_disp, root, 0); #else - on = 0; -#endif + 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 index de45c23..e94d5a3 100644 --- a/src/lib/ecore_x/xlib/ecore_x_selection.c +++ b/src/lib/ecore_x/xlib/ecore_x_selection.c @@ -1,8 +1,12 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -#include "ecore_private.h" +#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" @@ -11,14 +15,22 @@ static Ecore_X_Selection_Intern selections[4]; static Ecore_X_Selection_Converter *converters = NULL; static Ecore_X_Selection_Parser *parsers = NULL; -static int _ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret); -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); +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)) @@ -29,28 +41,28 @@ _ecore_x_selection_data_init(void) memset(selections, 0, sizeof(selections)); /* Initialize converters */ - ecore_x_selection_converter_atom_add(ECORE_X_ATOM_TEXT, - _ecore_x_selection_converter_text); + 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 + 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_text); ecore_x_selection_converter_atom_add(ECORE_X_ATOM_STRING, - _ecore_x_selection_converter_text); + ecore_x_selection_converter_text); /* Initialize parsers */ ecore_x_selection_parser_add("text/plain", - _ecore_x_selection_parser_text); + _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_text); ecore_x_selection_parser_add("text/uri-list", - _ecore_x_selection_parser_files); + _ecore_x_selection_parser_files); ecore_x_selection_parser_add("_NETSCAPE_URL", - _ecore_x_selection_parser_files); + _ecore_x_selection_parser_files); ecore_x_selection_parser_add(ECORE_X_SELECTION_TARGET_TARGETS, - _ecore_x_selection_parser_targets); + _ecore_x_selection_parser_targets); } void @@ -63,11 +75,11 @@ _ecore_x_selection_shutdown(void) cnv = converters; while (cnv) { - Ecore_X_Selection_Converter *tmp; + Ecore_X_Selection_Converter *tmp; - tmp = cnv->next; - free(cnv); - cnv = tmp; + tmp = cnv->next; + free(cnv); + cnv = tmp; } converters = NULL; @@ -75,12 +87,12 @@ _ecore_x_selection_shutdown(void) prs = parsers; while (prs) { - Ecore_X_Selection_Parser *tmp; + Ecore_X_Selection_Parser *tmp; - tmp = prs; - prs = prs->next; - free(tmp->target); - free(tmp); + tmp = prs; + prs = prs->next; + free(tmp->target); + free(tmp); } parsers = NULL; } @@ -100,16 +112,19 @@ _ecore_x_selection_get(Ecore_X_Atom selection) return NULL; } -int -_ecore_x_selection_set(Window w, const void *data, int size, Ecore_X_Atom selection) +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 0; - + return EINA_FALSE; + if (selection == ECORE_X_ATOM_SELECTION_PRIMARY) in = 0; else if (selection == ECORE_X_ATOM_SELECTION_SECONDARY) @@ -119,29 +134,27 @@ _ecore_x_selection_set(Window w, const void *data, int size, Ecore_X_Atom select else if (selection == ECORE_X_ATOM_SELECTION_CLIPBOARD) in = 3; else - return 0; + 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); - memcpy(buf, data, size); - selections[in].data = buf; + 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 + else if (selections[in].data) { - if (selections[in].data) - { - free(selections[in].data); - memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data)); - } + free(selections[in].data); + memset(&selections[in], 0, sizeof(Ecore_X_Selection_Data)); } - return 1; + return EINA_TRUE; } /** @@ -149,12 +162,15 @@ _ecore_x_selection_set(Window w, const void *data, int size, Ecore_X_Atom select * @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 + * @return Returns 1 if the ownership of the selection was successfully * claimed, or 0 if unsuccessful. */ -EAPI int -ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size) +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); } @@ -164,9 +180,10 @@ ecore_x_selection_primary_set(Ecore_X_Window w, const void *data, int size) * or 0 if unsuccessful. * */ -EAPI int +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); } @@ -175,13 +192,19 @@ ecore_x_selection_primary_clear(void) * @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 + * @return Returns 1 if the ownership of the selection was successfully * claimed, or 0 if unsuccessful. */ -EAPI int -ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size) +EAPI Eina_Bool +ecore_x_selection_secondary_set(Ecore_X_Window w, + const void *data, + int size) { - return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_SECONDARY); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, + data, + size, + ECORE_X_ATOM_SELECTION_SECONDARY); } /** @@ -190,10 +213,14 @@ ecore_x_selection_secondary_set(Ecore_X_Window w, const void *data, int size) * or 0 if unsuccessful. * */ -EAPI int +EAPI Eina_Bool ecore_x_selection_secondary_clear(void) { - return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_SECONDARY); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, + NULL, + 0, + ECORE_X_ATOM_SELECTION_SECONDARY); } /** @@ -201,12 +228,15 @@ ecore_x_selection_secondary_clear(void) * @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 + * @return Returns 1 if the ownership of the selection was successfully * claimed, or 0 if unsuccessful. */ -EAPI int -ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size) +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); } @@ -216,9 +246,10 @@ ecore_x_selection_xdnd_set(Ecore_X_Window w, const void *data, int size) * or 0 if unsuccessful. * */ -EAPI int +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); } @@ -227,16 +258,22 @@ ecore_x_selection_xdnd_clear(void) * @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 + * @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 int -ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size) +EAPI Eina_Bool +ecore_x_selection_clipboard_set(Ecore_X_Window w, + const void *data, + int size) { - return _ecore_x_selection_set(w, data, size, ECORE_X_ATOM_SELECTION_CLIPBOARD); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(w, + data, + size, + ECORE_X_ATOM_SELECTION_CLIPBOARD); } /** @@ -245,10 +282,14 @@ ecore_x_selection_clipboard_set(Ecore_X_Window w, const void *data, int size) * or 0 if unsuccessful. * */ -EAPI int +EAPI Eina_Bool ecore_x_selection_clipboard_clear(void) { - return _ecore_x_selection_set(None, NULL, 0, ECORE_X_ATOM_SELECTION_CLIPBOARD); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_selection_set(None, + NULL, + 0, + ECORE_X_ATOM_SELECTION_CLIPBOARD); } Ecore_X_Atom @@ -267,9 +308,7 @@ _ecore_x_selection_target_atom_get(const char *target) else if (!strcmp(target, ECORE_X_SELECTION_TARGET_FILENAME)) x_target = ECORE_X_ATOM_FILE_NAME; else - { - x_target = ecore_x_atom_get(target); - } + x_target = ecore_x_atom_get(target); return x_target; } @@ -291,8 +330,10 @@ _ecore_x_selection_target_get(Ecore_X_Atom target) return XGetAtomName(_ecore_x_disp, target); } -static void -_ecore_x_selection_request(Ecore_X_Window w, Ecore_X_Atom selection, const char *target_str) +static void +_ecore_x_selection_request(Ecore_X_Window w, + Ecore_X_Atom selection, + const char *target_str) { Ecore_X_Atom target, prop; @@ -308,83 +349,109 @@ _ecore_x_selection_request(Ecore_X_Window w, Ecore_X_Atom selection, const char return; XConvertSelection(_ecore_x_disp, selection, target, prop, - w, CurrentTime); + w, CurrentTime); } -EAPI void -ecore_x_selection_primary_request(Ecore_X_Window w, const char *target) +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) +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) +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); + ECORE_X_ATOM_SELECTION_PROP_XDND, w, + _target->time); } -EAPI void -ecore_x_selection_clipboard_request(Ecore_X_Window w, const char *target) +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, - int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret)) + 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) + 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)); - cnv = cnv->next; + 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)); - cnv = converters; + 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, - int (*func)(char *target, void *data, int size, void **data_ret, int *size_ret)) +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); @@ -395,23 +462,28 @@ 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; + 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; } } @@ -423,160 +495,194 @@ ecore_x_selection_converter_del(char *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 int -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_notify_send(Ecore_X_Window requestor, + Ecore_X_Atom selection, + Ecore_X_Atom target, + Ecore_X_Atom property, + Ecore_X_Time tim) { - XEvent xev; + 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 = time; + xnotify.time = tim; xnotify.send_event = True; xnotify.serial = 0; xev.xselection = xnotify; - return ((XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? 1 : 0); + return (XSendEvent(_ecore_x_disp, requestor, False, 0, &xev) > 0) ? EINA_TRUE : EINA_FALSE; } /* Locate and run conversion callback for specified selection target */ -EAPI int -ecore_x_selection_convert(Ecore_X_Atom selection, Ecore_X_Atom target, void **data_ret) +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; - int size; 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); - free(tgt_str); - if (r) - { - *data_ret = data; - return r; - } - else - return 0; - } + 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 0; + 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; - */ + /* 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 int -_ecore_x_selection_converter_text(char *target, void *data, int size, void **data_ret, int *size_ret) +EAPI 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 0; + 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 +#endif /* ifdef X_HAVE_UTF8_STRING */ else - return 0; + return EINA_FALSE; - if (!(mystr = strdup(data))) - return 0; + 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) + if (Xutf8TextListToTextProperty(_ecore_x_disp, &mystr, 1, style, + &text_prop) == Success) { - int bufsize = strlen((char *)text_prop.value) + 1; - *data_ret = malloc(bufsize); - memcpy(*data_ret, text_prop.value, bufsize); - *size_ret = bufsize; - XFree(text_prop.value); - free(mystr); - return 1; + 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 - if (XmbTextListToTextProperty(_ecore_x_disp, &mystr, 1, style, &text_prop) == Success) + +#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); - memcpy(*data_ret, text_prop.value, bufsize); - *size_ret = bufsize; - XFree(text_prop.value); - free(mystr); - return 1; + 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 + +#endif /* ifdef X_HAVE_UTF8_STRING */ else { - free(mystr); - return 0; + return EINA_TRUE; } } EAPI void ecore_x_selection_parser_add(const char *target, - void *(*func)(const char *target, void *data, int size, int format)) + 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) + 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)); - prs = prs->next; + 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)); - prs = parsers; + parsers = calloc(1, sizeof(Ecore_X_Selection_Parser)); + if (!parsers) return; + prs = parsers; } + prs->target = strdup(target); prs->parse = func; } @@ -589,45 +695,83 @@ ecore_x_selection_parser_del(const char *target) 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; + 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_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); - return sel; - } + 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; @@ -647,63 +791,85 @@ _ecore_x_selection_data_default_free(void *data) } static void * -_ecore_x_selection_parser_files(const char *target, void *_data, int size, int format __UNUSED__) +_ecore_x_selection_parser_files(const char *target, + void *_data, + int size, + int format __UNUSED__) { Ecore_X_Selection_Data_Files *sel; - char *data = _data; + 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++; - data = realloc(data, size); - data[size - 1] = 0; + /* 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++; - sel->files = realloc(sel->files, sel->num_files * sizeof(char *)); - sel->files[sel->num_files - 1] = strdup(tmp); - tmp[0] = 0; - i = 0; - } - } + 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++; - sel->files = realloc(sel->files, sel->num_files * sizeof(char *)); - sel->files[sel->num_files - 1] = strdup(tmp); + 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); @@ -722,33 +888,45 @@ _ecore_x_selection_data_files_free(void *data) sel = data; if (sel->files) { - for (i = 0; i < sel->num_files; i++) - free(sel->files[i]); - free(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_parser_text(const char *target __UNUSED__, + void *_data, + int size, + int format __UNUSED__) { Ecore_X_Selection_Data_Text *sel; - char *data = _data; + 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++; - data = realloc(data, size); - data[size - 1] = 0; + /* 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; } @@ -765,24 +943,33 @@ _ecore_x_selection_data_text_free(void *data) } static void * -_ecore_x_selection_parser_targets(const char *target __UNUSED__, void *data, int size, int format __UNUSED__) +_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]); - free(data); 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; } @@ -796,10 +983,13 @@ _ecore_x_selection_data_targets_free(void *data) if (sel->targets) { - for (i = 0; i < sel->num_targets; i++) - XFree(sel->targets[i]); - free(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 index feaaa27..0c7f546 100644 --- a/src/lib/ecore_x/xlib/ecore_x_sync.c +++ b/src/lib/ecore_x/xlib/ecore_x_sync.c @@ -1,9 +1,11 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * XSync code */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -16,9 +18,10 @@ ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter) 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); @@ -29,20 +32,128 @@ ecore_x_sync_alarm_new(Ecore_X_Sync_Counter counter) values.events = True; alarm = XSyncCreateAlarm(_ecore_x_disp, - XSyncCACounter | - XSyncCAValueType | - XSyncCAValue | - XSyncCATestType | - XSyncCADelta | - XSyncCAEvents, - &values); + XSyncCACounter | + XSyncCAValueType | + XSyncCAValue | + XSyncCATestType | + XSyncCADelta | + XSyncCAEvents, + &values); ecore_x_sync(); return alarm; } -EAPI int +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 index f80a28a..a4d40f6 100644 --- a/src/lib/ecore_x/xlib/ecore_x_test.c +++ b/src/lib/ecore_x/xlib/ecore_x_test.c @@ -1,112 +1,150 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#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 int +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; - + 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 0; - keycode = XKeysymToKeycode(_ecore_x_disp, keysym); + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return EINA_FALSE; + + keycode = XKeysymToKeycode(_ecore_x_disp, keysym); } - if (keycode == 0) return 0; - return XTestFakeKeyEvent(_ecore_x_disp, keycode, 1, 0); -#else - return 0; -#endif + + 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 int +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; - + 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 0; - keycode = XKeysymToKeycode(_ecore_x_disp, keysym); + keysym = XStringToKeysym(key); + if (keysym == NoSymbol) + return EINA_FALSE; + + keycode = XKeysymToKeycode(_ecore_x_disp, keysym); } - if (keycode == 0) return 0; - return XTestFakeKeyEvent(_ecore_x_disp, keycode, 0, 0); -#else - return 0; -#endif + + 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 int +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; - + 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 0; - keycode = XKeysymToKeycode(_ecore_x_disp, keysym); - if (XKeycodeToKeysym(_ecore_x_disp, keycode, 0) != keysym) - { - if (XKeycodeToKeysym(_ecore_x_disp, keycode, 1) == keysym) - shift = 1; - else - keycode = 0; - } - else - shift = 0; + 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; - static KeySym *keysyms; - static 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)); - XSync(_ecore_x_disp, False); - keycode = keycode_max - mod - 1; + 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, + 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 1; -#else - return 0; -#endif + 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 * @@ -114,3 +152,16 @@ 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 index 517fcac..f16f5b1 100644 --- a/src/lib/ecore_x/xlib/ecore_x_window.c +++ b/src/lib/ecore_x/xlib/ecore_x_window.c @@ -1,12 +1,17 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#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 int ignore_num = 0; static Ecore_X_Window *ignore_list = NULL; /** @@ -27,51 +32,60 @@ static Ecore_X_Window *ignore_list = NULL; * @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_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { - Window win; + Window win; XSetWindowAttributes attr; - - 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; + + 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; + 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 | + 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); + CWBorderPixel | + CWBackPixmap | + CWSaveUnder | + CWDontPropagate | + CWEventMask | + CWBitGravity | + CWWinGravity, + &attr); + + if (parent == DefaultRootWindow(_ecore_x_disp)) + ecore_x_window_defaults_set(win); + return win; } @@ -87,49 +101,56 @@ ecore_x_window_new(Ecore_X_Window parent, int x, int y, int w, int h) * @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_override_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { - Window win; + Window win; XSetWindowAttributes attr; - - 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; + + 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; + 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 | + 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); + CWBorderPixel | + CWBackPixmap | + CWSaveUnder | + CWDontPropagate | + CWEventMask | + CWBitGravity | + CWWinGravity, + &attr); return win; } @@ -145,45 +166,53 @@ ecore_x_window_override_new(Ecore_X_Window parent, int x, int y, int w, int h) * @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_input_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { - Window win; + Window win; XSetWindowAttributes attr; - - if (parent == 0) parent = DefaultRootWindow(_ecore_x_disp); - attr.override_redirect = True; + + 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; + 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); + 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 Evas_X_Window_Properties_Group X Window Property Functions + * @defgroup Ecore_X_Window_Properties_Group X Window Property Functions * * Functions that set window properties. */ @@ -195,7 +224,7 @@ ecore_x_window_input_new(Ecore_X_Window parent, int x, int y, int w, int h) * @c _NET_WM_PID. * * @param win The given window. - * @ingroup Evas_X_Window_Properties_Groups + * @ingroup Ecore_X_Window_Properties_Group */ EAPI void ecore_x_window_defaults_set(Ecore_X_Window win) @@ -207,6 +236,7 @@ ecore_x_window_defaults_set(Ecore_X_Window win) char **argv; XTextProperty xprop; + LOGFN(__FILE__, __LINE__, __FUNCTION__); /* * Set WM_CLIENT_MACHINE. */ @@ -216,11 +246,11 @@ ecore_x_window_defaults_set(Ecore_X_Window win) /* 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); */ + (char *)buf); */ if (XStringListToTextProperty(hostname, 1, &xprop)) { - XSetWMClientMachine(_ecore_x_disp, win, &xprop); - XFree(xprop.value); + XSetWMClientMachine(_ecore_x_disp, win, &xprop); + XFree(xprop.value); } /* @@ -238,14 +268,20 @@ ecore_x_window_defaults_set(Ecore_X_Window win) 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 x, + int y, + int w, + int h, + int border_width, + Ecore_X_Window sibling, int stack_mode) { XWindowChanges xwc; if (!win) - return; + return; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); xwc.x = x; xwc.y = y; @@ -259,7 +295,7 @@ ecore_x_window_configure(Ecore_X_Window win, } /** - * @defgroup Evas_X_Window_Destroy_Group X Window Destroy Functions + * @defgroup Ecore_X_Window_Destroy_Group X Window Destroy Functions * * Functions to destroy X windows. */ @@ -267,16 +303,17 @@ ecore_x_window_configure(Ecore_X_Window win, /** * Deletes the given window. * @param win The given window. - * @ingroup Evas_X_Window_Destroy_Group + * @ingroup Ecore_X_Window_Destroy_Group */ EAPI void -ecore_x_window_del(Ecore_X_Window win) +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); + XDestroyWindow(_ecore_x_disp, win); } /** @@ -285,41 +322,56 @@ ecore_x_window_del(Ecore_X_Window win) * @param ignore if to ignore */ EAPI void -ecore_x_window_ignore_set(Ecore_X_Window win, int ignore) +ecore_x_window_ignore_set(Ecore_X_Window win, + int ignore) { - int i, j; + 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; - } - 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)); - ignore_list[ignore_num++] = win; - } + 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 (i = 0, j = 0; i < ignore_num; i++) - { - if (win != ignore_list[i]) - ignore_list[i] = ignore_list[j++]; - else - ignore_num--; - } - ignore_list = realloc(ignore_list, ignore_num * sizeof(Ecore_X_Window)); + 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; } } @@ -331,14 +383,16 @@ ecore_x_window_ignore_set(Ecore_X_Window win, int ignore) EAPI Ecore_X_Window * ecore_x_window_ignore_list(int *num) { - if (num) *num = ignore_num; + if (num) + *num = ignore_num; + return ignore_list; } /** * Sends a delete request to the given window. * @param win The given window. - * @ingroup Evas_X_Window_Destroy_Group + * @ingroup Ecore_X_Window_Destroy_Group */ EAPI void ecore_x_window_delete_request_send(Ecore_X_Window win) @@ -349,8 +403,9 @@ ecore_x_window_delete_request_send(Ecore_X_Window win) * a smart idea. */ if (!win) - return; + return; + LOGFN(__FILE__, __LINE__, __FUNCTION__); xev.xclient.type = ClientMessage; xev.xclient.display = _ecore_x_disp; xev.xclient.window = win; @@ -363,7 +418,7 @@ ecore_x_window_delete_request_send(Ecore_X_Window win) } /** - * @defgroup Evas_X_Window_Visibility_Group X Window Visibility Functions + * @defgroup Ecore_X_Window_Visibility_Group X Window Visibility Functions * * Functions to access and change the visibility of X windows. */ @@ -374,11 +429,12 @@ ecore_x_window_delete_request_send(Ecore_X_Window win) * Synonymous to "mapping" a window in X Window System terminology. * * @param win The window to show. - * @ingroup Evas_X_Window_Visibility + * @ingroup Ecore_X_Window_Visibility */ EAPI void ecore_x_window_show(Ecore_X_Window win) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XMapWindow(_ecore_x_disp, win); } @@ -388,7 +444,7 @@ ecore_x_window_show(Ecore_X_Window win) * Synonymous to "unmapping" a window in X Window System terminology. * * @param win The window to hide. - * @ingroup Evas_X_Window_Visibility + * @ingroup Ecore_X_Window_Visibility */ EAPI void ecore_x_window_hide(Ecore_X_Window win) @@ -399,11 +455,21 @@ ecore_x_window_hide(Ecore_X_Window win) 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); + 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; @@ -412,7 +478,7 @@ ecore_x_window_hide(Ecore_X_Window win) xev.xunmap.window = win; xev.xunmap.from_configure = False; XSendEvent(_ecore_x_disp, xev.xunmap.event, False, - SubstructureRedirectMask | SubstructureNotifyMask, &xev); + SubstructureRedirectMask | SubstructureNotifyMask, &xev); XUnmapWindow(_ecore_x_disp, win); } @@ -434,8 +500,11 @@ ecore_x_window_hide(Ecore_X_Window win) * @ingroup Ecore_X_Window_Geometry_Group */ EAPI void -ecore_x_window_move(Ecore_X_Window win, int x, int y) +ecore_x_window_move(Ecore_X_Window win, + int x, + int y) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XMoveWindow(_ecore_x_disp, win, x, y); } @@ -447,10 +516,17 @@ ecore_x_window_move(Ecore_X_Window win, int x, int y) * @ingroup Ecore_X_Window_Geometry_Group */ EAPI void -ecore_x_window_resize(Ecore_X_Window win, int w, int h) +ecore_x_window_resize(Ecore_X_Window win, + int w, + int h) { - if (w < 1) w = 1; - if (h < 1) h = 1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (w < 1) + w = 1; + + if (h < 1) + h = 1; + XResizeWindow(_ecore_x_disp, win, w, h); } @@ -464,10 +540,19 @@ ecore_x_window_resize(Ecore_X_Window win, int w, int h) * @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) +ecore_x_window_move_resize(Ecore_X_Window win, + int x, + int y, + int w, + int h) { - if (w < 1) w = 1; - if (h < 1) h = 1; + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (w < 1) + w = 1; + + if (h < 1) + h = 1; + XMoveResizeWindow(_ecore_x_disp, win, x, y, w, h); } @@ -485,9 +570,12 @@ 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) { - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); -// XSetInputFocus(_ecore_x_disp, win, RevertToNone, CurrentTime); - XSetInputFocus(_ecore_x_disp, win, RevertToPointerRoot, CurrentTime); + 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); } /** @@ -497,15 +585,19 @@ ecore_x_window_focus(Ecore_X_Window win) * @ingroup Ecore_X_Window_Focus_Functions */ EAPI void -ecore_x_window_focus_at_time(Ecore_X_Window win, Ecore_X_Time t) +ecore_x_window_focus_at_time(Ecore_X_Window win, + Ecore_X_Time t) { - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); -// XSetInputFocus(_ecore_x_disp, win, RevertToNone, t); - XSetInputFocus(_ecore_x_disp, win, PointerRoot, 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 focus to the window @p win. + * gets the window that has focus. * @return The window that has focus. * @ingroup Ecore_X_Window_Focus_Functions */ @@ -514,9 +606,9 @@ 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; } @@ -535,6 +627,7 @@ ecore_x_window_focus_get(void) EAPI void ecore_x_window_raise(Ecore_X_Window win) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XRaiseWindow(_ecore_x_disp, win); } @@ -546,6 +639,7 @@ ecore_x_window_raise(Ecore_X_Window win) EAPI void ecore_x_window_lower(Ecore_X_Window win) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); XLowerWindow(_ecore_x_disp, win); } @@ -564,9 +658,15 @@ ecore_x_window_lower(Ecore_X_Window win) * @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) +ecore_x_window_reparent(Ecore_X_Window win, + Ecore_X_Window new_parent, + int x, + int y) { - if (new_parent == 0) new_parent = DefaultRootWindow(_ecore_x_disp); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (new_parent == 0) + new_parent = DefaultRootWindow(_ecore_x_disp); + XReparentWindow(_ecore_x_disp, win, new_parent, x, y); } @@ -578,18 +678,28 @@ ecore_x_window_reparent(Ecore_X_Window win, Ecore_X_Window new_parent, int x, in * @ingroup Ecore_X_Window_Geometry_Group */ EAPI void -ecore_x_window_size_get(Ecore_X_Window win, int *w, int *h) +ecore_x_window_size_get(Ecore_X_Window win, + int *w, + int *h) { int dummy_x, dummy_y; - - if (win == 0) - win = DefaultRootWindow(_ecore_x_disp); + + 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. @@ -598,10 +708,15 @@ ecore_x_window_size_get(Ecore_X_Window win, int *w, int *h) * @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) +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); + win = DefaultRootWindow(_ecore_x_disp); ecore_x_drawable_geometry_get(win, x, y, w, h); } @@ -615,9 +730,10 @@ 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) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); /* doesn't make sense to call this on a root window */ if (!win) - return 0; + return 0; return ecore_x_drawable_border_width_get(win); } @@ -629,11 +745,13 @@ ecore_x_window_border_width_get(Ecore_X_Window win) * @ingroup Ecore_X_Window_Geometry_Group */ EAPI void -ecore_x_window_border_width_set(Ecore_X_Window win, int width) +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; + return; XSetWindowBorderWidth (_ecore_x_disp, win, width); } @@ -646,47 +764,52 @@ ecore_x_window_border_width_set(Ecore_X_Window win, int width) EAPI int ecore_x_window_depth_get(Ecore_X_Window win) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); return ecore_x_drawable_depth_get(win); } - + /** - * To be documented. - * - * FIXME: To be fixed. + * @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, int show) +ecore_x_window_cursor_show(Ecore_X_Window win, + Eina_Bool show) { - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); + 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); + 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); - } + XDefineCursor(_ecore_x_disp, win, 0); } EAPI void -ecore_x_window_cursor_set(Ecore_X_Window win, Ecore_X_Cursor c) +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 @@ -704,84 +827,92 @@ ecore_x_window_visible_get(Ecore_X_Window win) { XWindowAttributes attr; - return (XGetWindowAttributes(_ecore_x_disp, win, &attr) && - (attr.map_state == IsViewable)); + 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; + Shadow *parent; + Shadow **children; + Window win; + int children_num; + short x, y; + unsigned short w, h; }; -static int shadow_count = 0; 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; - int i, j; - unsigned int num; - Shadow *s, **sl; + 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; - + 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; + 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)) + &list, &num)) { - 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; - } - } + 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; } @@ -790,16 +921,19 @@ _ecore_x_window_tree_shadow_free1(Shadow *s) { int i; - if (!s) return; + 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); + 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); } @@ -807,12 +941,16 @@ static void _ecore_x_window_tree_shadow_free(void) { int i; - - if (!shadow_base) return; + + 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]); + if (!shadow_base[i]) + continue; + + _ecore_x_window_tree_shadow_free1(shadow_base[i]); } free(shadow_base); shadow_base = NULL; @@ -822,59 +960,69 @@ _ecore_x_window_tree_shadow_free(void) static void _ecore_x_window_tree_shadow_populate(void) { - Ecore_X_Window *roots; - int i, num; - + 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); + 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) -{ +/* + 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) -{ + 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, Window win) +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->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; - } - } + 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 * +static Shadow * _ecore_x_window_shadow_tree_find(Window base) { Shadow *s; @@ -882,71 +1030,138 @@ _ecore_x_window_shadow_tree_find(Window base) 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; + 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) +_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; - } - } - } + 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) +_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; + _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); + if (!s) + return 0; + + return _ecore_x_window_shadow_tree_at_xy_get_shadow(s, + bx, + by, + x, + y, + skip, + skip_num); } /** @@ -958,13 +1173,26 @@ _ecore_x_window_shadow_tree_at_xy_get(Window base, int bx, int by, int x, int y, * @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) +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); + LOGFN(__FILE__, __LINE__, __FUNCTION__); + return _ecore_x_window_shadow_tree_at_xy_get(base, + 0, + 0, + x, + y, + skip, + skip_num); } /** @@ -976,25 +1204,33 @@ ecore_x_window_shadow_tree_at_xy_with_skip_get(Ecore_X_Window base, int x, int y * @ingroup Ecore_X_Window_Geometry_Group */ EAPI Ecore_X_Window -ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win) +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; + _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; - } + 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; } @@ -1006,6 +1242,7 @@ ecore_x_window_shadow_parent_get(Ecore_X_Window root, Ecore_X_Window win) EAPI void ecore_x_window_shadow_tree_flush(void) { + LOGFN(__FILE__, __LINE__, __FUNCTION__); _ecore_x_window_tree_shadow_free(); } @@ -1020,22 +1257,32 @@ ecore_x_window_root_get(Ecore_X_Window win) { XWindowAttributes att; - if (!XGetWindowAttributes(_ecore_x_disp, win, &att)) return 0; + 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) +_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; + 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; @@ -1043,40 +1290,41 @@ _ecore_x_window_at_xy_get(Window base, int bx, int by, int x, int y, 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); + 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; } @@ -1088,18 +1336,20 @@ _ecore_x_window_at_xy_get(Window base, int bx, int by, int x, int y, * @ingroup Ecore_X_Window_Geometry_Group */ EAPI Ecore_X_Window -ecore_x_window_at_xy_get(int x, int y) +ecore_x_window_at_xy_get(int x, + int y) { - Ecore_X_Window win, root; - + 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; } @@ -1108,34 +1358,43 @@ ecore_x_window_at_xy_get(int x, int y) * 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_at_xy_with_skip_get(int x, + int y, + Ecore_X_Window *skip, + int skip_num) { - Ecore_X_Window win, root; - + 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_at_xy_begin_get(Ecore_X_Window begin, + int x, + int y) { - Ecore_X_Window win; - + 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; } @@ -1148,13 +1407,15 @@ 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) { - Window root, parent, *children = NULL; - unsigned int num; + Window root, parent, *children = NULL; + unsigned int num; + LOGFN(__FILE__, __LINE__, __FUNCTION__); if (!XQueryTree(_ecore_x_disp, win, &root, &parent, &children, &num)) - return 0; + return 0; + if (children) - XFree(children); + XFree(children); return parent; } @@ -1167,13 +1428,16 @@ ecore_x_window_parent_get(Ecore_X_Window win) * @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) +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; @@ -1186,164 +1450,201 @@ ecore_x_window_background_color_set(Ecore_X_Window win, unsigned short r, } EAPI void -ecore_x_window_gravity_set(Ecore_X_Window win, Ecore_X_Gravity grav) +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) +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) +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) +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) +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, int override) +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 +#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, int override, int saveunder) +_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; - + 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); + 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; - } - } + /* 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 == NULL) return 0; + 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; - } + 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.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; + 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); + 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); + if (parent == DefaultRootWindow(_ecore_x_disp)) + ecore_x_window_defaults_set(win); + return win; } -#endif + +#endif /* ifdef ECORE_XRENDER */ EAPI int ecore_x_window_argb_get(Ecore_X_Window win) { -#ifdef ECORE_XRENDER +#ifdef ECORE_XRENDER XWindowAttributes att; XRenderPictFormat *fmt; - - XGetWindowAttributes(_ecore_x_disp, win, &att); + + 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; + if (!fmt) + return 0; + + if ((fmt->type == PictTypeDirect) && (fmt->direct.alphaMask)) + return 1; + return 0; -#else +#else /* ifdef ECORE_XRENDER */ return 0; -#endif +#endif /* ifdef ECORE_XRENDER */ } /** @@ -1358,13 +1659,18 @@ ecore_x_window_argb_get(Ecore_X_Window win) * @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_manager_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { -#ifdef ECORE_XRENDER +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0); -#else +#else /* ifdef ECORE_XRENDER */ return 0; -#endif +#endif /* ifdef ECORE_XRENDER */ } /** @@ -1379,13 +1685,18 @@ ecore_x_window_manager_argb_new(Ecore_X_Window parent, int x, int y, int w, int * @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_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { -#ifdef ECORE_XRENDER +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 0, 0); -#else +#else /* ifdef ECORE_XRENDER */ return 0; -#endif +#endif /* ifdef ECORE_XRENDER */ } /** @@ -1400,11 +1711,17 @@ ecore_x_window_argb_new(Ecore_X_Window parent, int x, int y, int w, int h) * @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_override_argb_new(Ecore_X_Window parent, + int x, + int y, + int w, + int h) { -#ifdef ECORE_XRENDER +#ifdef ECORE_XRENDER + LOGFN(__FILE__, __LINE__, __FUNCTION__); return _ecore_x_window_argb_internal_new(parent, x, y, w, h, 1, 0); -#else +#else /* ifdef ECORE_XRENDER */ return 0; -#endif +#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 index 6081680..a582453 100644 --- a/src/lib/ecore_x/xlib/ecore_x_window_prop.c +++ b/src/lib/ecore_x/xlib/ecore_x_window_prop.c @@ -1,6 +1,10 @@ -/* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -8,31 +12,35 @@ #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) +#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) +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 - long *v2; - unsigned int i; +#else /* if SIZEOF_INT == SIZEOF_LONG */ + long *v2; + unsigned int i; + LOGFN(__FILE__, __LINE__, __FUNCTION__); v2 = malloc(num * sizeof(long)); if (!v2) - return; + return; + for (i = 0; i < num; i++) - v2[i] = val[i]; + v2[i] = val[i]; _ATOM_SET_CARD32(win, atom, v2, num); free(v2); -#endif +#endif /* if SIZEOF_INT == SIZEOF_LONG */ } /* @@ -44,36 +52,41 @@ ecore_x_window_prop_card32_set(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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; - + 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; - XGetWindowProperty(_ecore_x_disp, win, atom, 0, 0x7fffffff, False, - XA_CARDINAL, &type_ret, &format_ret, &num_ret, - &bytes_after, &prop_ret); - if (prop_ret && type_ret == XA_CARDINAL && format_ret == 32) - { - if (num_ret < len) - len = num_ret; - - for (i = 0; i < len; i++) - val[i] = ((unsigned long*)prop_ret)[i]; - - num = len; - } + 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 { - num = -1; + 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); + XFree(prop_ret); return num; } @@ -86,42 +99,45 @@ ecore_x_window_prop_card32_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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; - + 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 == None || num_ret == 0) - { - num = 0; - *plst = NULL; - } - else if (prop_ret && type_ret == XA_CARDINAL && format_ret == 32) - { - val = malloc(num_ret * sizeof(unsigned int)); - for (i = 0; i < num_ret; i++) - val[i] = ((unsigned long *)prop_ret)[i]; - num = num_ret; - *plst = val; - } + 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 { - num = -1; - *plst = NULL; + 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); + XFree(prop_ret); return num; } @@ -130,26 +146,30 @@ ecore_x_window_prop_card32_list_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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 - unsigned long *pl; - unsigned int i; + (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; + return; + for (i = 0; i < num; i++) - pl[i] = lst[i]; + pl[i] = lst[i]; XChangeProperty(_ecore_x_disp, win, atom, type, 32, PropModeReplace, - (unsigned char *)pl, num); + (unsigned char *)pl, num); free(pl); -#endif +#endif /* if SIZEOF_INT == SIZEOF_LONG */ } /* @@ -161,41 +181,42 @@ ecore_x_window_prop_xid_set(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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; - + 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 == None) - { - num = 0; - } - else if (prop_ret && type_ret == type && format_ret == 32) - { - if (num_ret < len) - len = num_ret; - for (i = 0; i < len; i++) - lst[i] = ((unsigned long *)prop_ret)[i]; - num = len; - } + 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 { - num = -1; + 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); + XFree(prop_ret); return num; } @@ -209,42 +230,42 @@ ecore_x_window_prop_xid_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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; - + 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 == None || num_ret == 0) - { - num = 0; - } - else if (prop_ret && type_ret == type && format_ret == 32) - { - alst = malloc(num_ret * sizeof(Ecore_X_ID)); - for (i = 0; i < num_ret; i++) - alst[i] = ((unsigned long *)prop_ret)[i]; - *val = alst; - num = num_ret; - } + 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 { - num = -1; + 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); + XFree(prop_ret); return num; } @@ -253,58 +274,67 @@ ecore_x_window_prop_xid_list_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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_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; + 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 */ + { + return; /* Error - assuming invalid window */ + } /* Is it there? */ for (i = 0; i < num; i++) { - if (lst[i] == item) - break; + 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]; + /* 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; + /* 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: +done: if (lst) - free(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) +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); } @@ -317,9 +347,12 @@ ecore_x_window_prop_atom_set(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } @@ -332,9 +365,11 @@ ecore_x_window_prop_atom_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } @@ -342,9 +377,12 @@ ecore_x_window_prop_atom_list_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } @@ -352,9 +390,12 @@ ecore_x_window_prop_atom_list_change(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } @@ -367,9 +408,12 @@ ecore_x_window_prop_window_set(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } @@ -382,17 +426,14 @@ ecore_x_window_prop_window_get(Ecore_X_Window win, Ecore_X_Atom atom, * 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) +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); } -/** - * To be documented. - * - * FIXME: To be fixed. - */ EAPI Ecore_X_Atom ecore_x_window_prop_any_type(void) { @@ -400,40 +441,71 @@ ecore_x_window_prop_any_type(void) } /** - * To be documented. - * - * FIXME: To be fixed. + * @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) +ecore_x_window_prop_property_set(Ecore_X_Window win, + Ecore_X_Atom property, + Ecore_X_Atom type, + int size, + void *data, + int number) { - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); + 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); + 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); - } + 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); + } } } /** - * To be documented. - * - * FIXME: To be fixed. + * @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) +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; @@ -441,77 +513,95 @@ ecore_x_window_prop_property_get(Ecore_X_Window win, Ecore_X_Atom property, Ecor unsigned char *prop_ret = NULL; /* make sure these are initialized */ - if (num) *num = 0; + if (num) + *num = 0; if (data) *data = NULL; else /* we can't store the retrieved data, so just return */ return 0; - if (!win) win = DefaultRootWindow(_ecore_x_disp); + 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; - } - + 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; + 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; + 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; - } + 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; + if (num) + *num = num_ret; + return size_ret; } EAPI void -ecore_x_window_prop_property_del(Ecore_X_Window win, Ecore_X_Atom property) +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_window_prop_list(Ecore_X_Window win, + int *num_ret) { Ecore_X_Atom *atoms; Atom *atom_ret; int num = 0, i; - - if (num_ret) *num_ret = 0; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (num_ret) + *num_ret = 0; atom_ret = XListProperties(_ecore_x_disp, win, &num); - if (!atom_ret) return NULL; + 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; + for (i = 0; i < num; i++) + atoms[i] = atom_ret[i]; + if (num_ret) + *num_ret = num; } + XFree(atom_ret); return atoms; } @@ -521,15 +611,20 @@ ecore_x_window_prop_list(Ecore_X_Window win, int *num_ret) * @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) +ecore_x_window_prop_string_set(Ecore_X_Window win, + Ecore_X_Atom type, + const char *str) { - XTextProperty xtp; + XTextProperty xtp; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); - if (win == 0) win = DefaultRootWindow(_ecore_x_disp); xtp.value = (unsigned char *)str; xtp.format = 8; xtp.encoding = ECORE_X_ATOM_UTF8_STRING; @@ -541,74 +636,76 @@ ecore_x_window_prop_string_set(Ecore_X_Window win, Ecore_X_Atom type, const char * 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. + * @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) +ecore_x_window_prop_string_get(Ecore_X_Window win, + Ecore_X_Atom type) { - XTextProperty xtp; - char *str = NULL; + XTextProperty xtp; + char *str = NULL; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (win == 0) + win = DefaultRootWindow(_ecore_x_disp); - 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 - { + 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 - s = XmbTextPropertyToTextList(_ecore_x_disp, &xtp, - &list, &items); -#endif - 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); + 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 int +EAPI Eina_Bool ecore_x_window_prop_protocol_isset(Ecore_X_Window win, Ecore_X_WM_Protocol protocol) { Atom proto, *protos = NULL; - int i, ret = 0, protos_count = 0; + int i, protos_count = 0; + Eina_Bool ret = EINA_FALSE; /* check for invalid values */ if (protocol >= ECORE_X_WM_PROTOCOL_NUM) - return 0; + 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; + return ret; for (i = 0; i < protos_count; i++) - if (protos[i] == proto) - { - ret = 1; - break; - } + if (protos[i] == proto) + { + ret = EINA_TRUE; + break; + } XFree(protos); @@ -616,39 +713,48 @@ ecore_x_window_prop_protocol_isset(Ecore_X_Window win, } /** - * To be documented. - * - * FIXME: To be fixed. + * @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) +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; + 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; + 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; - } + 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 index 2e30587..71718cf 100644 --- a/src/lib/ecore_x/xlib/ecore_x_window_shape.c +++ b/src/lib/ecore_x/xlib/ecore_x_window_shape.c @@ -1,3 +1,9 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -17,173 +23,636 @@ * @ingroup Ecore_X_Window_Shape */ EAPI void -ecore_x_window_shape_mask_set(Ecore_X_Window win, Ecore_X_Pixmap mask) +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_window_set(Ecore_X_Window win, Ecore_X_Window shape_win) +ecore_x_window_shape_input_window_set_xy(Ecore_X_Window win, + Ecore_X_Window shape_win, + int x, + int y) { - XShapeCombineShape(_ecore_x_disp, win, ShapeBounding, 0, 0, shape_win, ShapeBounding, ShapeSet); +#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_window_set_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y) +ecore_x_window_shape_rectangle_set(Ecore_X_Window win, + int x, + int y, + int w, + int h) { - XShapeCombineShape(_ecore_x_disp, win, ShapeBounding, x, y, shape_win, ShapeBounding, ShapeSet); + 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_rectangle_set(Ecore_X_Window win, int x, int y, int w, int h) +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, ShapeBounding, 0, 0, &rect, 1, ShapeSet, Unsorted); + 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) +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) - { - 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; - } - } - else - 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); + 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_window_add(Ecore_X_Window win, Ecore_X_Window shape_win) +ecore_x_window_shape_input_rectangles_set(Ecore_X_Window win, + Ecore_X_Rectangle *rects, + int num) { - XShapeCombineShape(_ecore_x_disp, win, ShapeBounding, 0, 0, shape_win, ShapeBounding, ShapeUnion); +#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_window_add_xy(Ecore_X_Window win, Ecore_X_Window shape_win, int x, int y) +ecore_x_window_shape_rectangle_subtract(Ecore_X_Window win, + int x, + int y, + int w, + int h) { - XShapeCombineShape(_ecore_x_disp, win, ShapeBounding, x, y, shape_win, ShapeBounding, ShapeUnion); + 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_rectangle_add(Ecore_X_Window win, int x, int y, int w, int h) +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, ShapeBounding, 0, 0, &rect, 1, ShapeUnion, Unsorted); + 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_rectangle_clip(Ecore_X_Window win, int x, int y, int w, int h) +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, ShapeIntersect, Unsorted); + XShapeCombineRectangles(_ecore_x_disp, + win, + ShapeBounding, + 0, + 0, + &rect, + 1, + ShapeUnion, + Unsorted); } EAPI void -ecore_x_window_shape_rectangles_add(Ecore_X_Window win, Ecore_X_Rectangle *rects, int num) +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) - { - 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; - } - } - else - 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); + + 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) +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) { - rects = malloc(sizeof(Ecore_X_Rectangle) * num); - if (rects) - { - 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 < 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, int on) +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); } -/** - * Sets the input 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 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) -{ -#ifdef ShapeInput - XShapeCombineMask(_ecore_x_disp, win, ShapeInput, 0, 0, mask, ShapeSet); -#else - XShapeCombineMask(_ecore_x_disp, win, ShapeBounding, 0, 0, mask, ShapeSet); -#endif -} - 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 100755 index 0000000..a09f055 --- /dev/null +++ b/src/lib/ecore_x/xlib/ecore_x_xi2.c @@ -0,0 +1,556 @@ +#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 +#ifdef ECORE_XI2_2 +#ifndef XITouchEmulatingPointer +#define XITouchEmulatingPointer (1 << 17) +#endif + +typedef struct _Ecore_X_Touch_Device_Info +{ + EINA_INLIST; + int devid; + int mode; + const char *name; + int max_touch; + int *slot; +} Ecore_X_Touch_Device_Info; +#endif /* ifdef ECORE_XI2_2 */ + +static XIDeviceInfo *_ecore_x_xi2_devs = NULL; +static int _ecore_x_xi2_num = 0; +#ifdef ECORE_XI2_2 +static Eina_Inlist *_ecore_x_xi2_touch_info_list = NULL; +#endif /* ifdef ECORE_XI2_2 */ +#endif /* ifdef ECORE_XI2 */ + +void +_ecore_x_input_init(void) +{ +#ifdef ECORE_XI2 + int event, error; + int major = XI_2_Major, minor = XI_2_Minor; + + 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 */ +} + +#ifdef ECORE_XI2 +#ifdef ECORE_XI2_2 +static void +_ecore_x_input_touch_info_clear(void) +{ + Eina_Inlist *l = _ecore_x_xi2_touch_info_list; + Ecore_X_Touch_Device_Info *info = NULL; + + while (l) + { + info = EINA_INLIST_CONTAINER_GET(l, Ecore_X_Touch_Device_Info); + l = eina_inlist_remove(l, l); + if (info->slot) free(info->slot); + free(info); + } + + _ecore_x_xi2_touch_info_list = NULL; +} +#endif /* ifdef ECORE_XI2_2 */ +#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; +#ifdef ECORE_XI2_2 + _ecore_x_input_touch_info_clear(); +#endif /* ifdef ECORE_XI2_2 */ + } + + _ecore_x_xi2_num = 0; + _ecore_x_xi2_opcode = -1; +#endif /* ifdef ECORE_XI2 */ +} + +#ifdef ECORE_XI2 +#ifdef ECORE_XI2_2 +static int +_ecore_x_input_touch_index_get(int devid, int detail, int event_type) +{ + int i; + Eina_Inlist *l = _ecore_x_xi2_touch_info_list; + Ecore_X_Touch_Device_Info *info = NULL; + + if ((!_ecore_x_xi2_devs) || (!_ecore_x_xi2_touch_info_list)) + return 0; + + EINA_INLIST_FOREACH(l, info) + if (info->devid == devid) break; + + if ((!info) || (!info->slot)) return 0; + + for (i = 0; i < info->max_touch ; i++) + { + int *p = &(info->slot[i]); + + if ((event_type == XI_TouchBegin) && (*p < 0)) + { + *p = detail; + return i; + } + else if (*p == detail) + { + return i; + } + } + + return 0; +} + +static void +_ecore_x_input_touch_index_clear(int devid, int idx) +{ + Eina_Inlist *l = _ecore_x_xi2_touch_info_list; + Ecore_X_Touch_Device_Info *info = NULL; + + if ((!_ecore_x_xi2_devs) || (!_ecore_x_xi2_touch_info_list)) + return; + + EINA_INLIST_FOREACH(l, info) + { + if ((info->devid == devid) && (info->slot)) + { + info->slot[idx] = -1; + return; + } + } +} + +static Ecore_X_Touch_Device_Info * +_ecore_x_input_touch_info_get(XIDeviceInfo *dev) +{ + int k; + int *slot = NULL; + XITouchClassInfo *t = NULL; + Ecore_X_Touch_Device_Info *info = NULL; + + if (!dev) + return NULL; + + for (k = 0; k < dev->num_classes; k++) + { + XIAnyClassInfo *clas = dev->classes[k]; + + if (clas && (clas->type == XITouchClass)) + { + t = (XITouchClassInfo *)clas; + break; + } + } + + if (t && (t->type == XITouchClass)) + { + info = calloc(1, sizeof(Ecore_X_Touch_Device_Info)); + if (!info) return NULL; + + slot = malloc(sizeof(int) * (t->num_touches + 1)); + if (!slot) + { + free(info); + return NULL; + } + + info->devid = dev->deviceid; + info->max_touch = t->num_touches + 1; + info->mode = t->mode; + info->name = dev->name; + memset(slot, -1, sizeof(int) * info->max_touch); + info->slot = slot; + } + + return info; +} +#endif /* ifdef ECORE_XI2_2 */ +#endif + +void +_ecore_x_input_handler(XEvent *xevent) +{ +#ifdef ECORE_XI2 + XIDeviceEvent *evd = (XIDeviceEvent *)(xevent->xcookie.data); + /* XIRawEvent *evr = (XIRawEvent *)(xevent->xcookie.data); */ + int devid = evd->deviceid; + int i; + + /* No filter for this events */ + switch (xevent->xcookie.evtype) + { +#ifdef XI_RawButtonPress + case XI_RawButtonPress: + ecore_event_add(ECORE_X_RAW_BUTTON_PRESS, NULL, NULL, NULL); + break; +#endif +#ifdef XI_RawButtonRelease + case XI_RawButtonRelease: + ecore_event_add(ECORE_X_RAW_BUTTON_RELEASE, NULL, NULL, NULL); + break; +#endif +#ifdef XI_RawMotion + case XI_RawMotion: + ecore_event_add(ECORE_X_RAW_MOTION, NULL, NULL, NULL); + break; +#endif + } + + 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: +#ifdef ECORE_XI2_2 + i = _ecore_x_input_touch_index_get(devid, evd->detail, XI_TouchUpdate); + if ((i == 0) && (evd->flags & XITouchEmulatingPointer)) return; +#endif /* #ifdef ECORE_XI2_2 */ + _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 +#ifdef ECORE_XI2_2 + i, 1, 1, +#else + devid, 1, 1, +#endif /* #ifdef ECORE_XI2_2 */ + 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: +#ifdef ECORE_XI2_2 + i = _ecore_x_input_touch_index_get(devid, evd->detail, XI_TouchBegin); + if ((i == 0) && (evd->flags & XITouchEmulatingPointer)) return; +#endif /* #ifdef ECORE_XI2_2 */ + _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 +#ifdef ECORE_XI2_2 + i, 1, 1, +#else + devid, 1, 1, +#endif /* #ifdef ECORE_XI2_2 */ + 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: +#ifdef ECORE_XI2_2 + i = _ecore_x_input_touch_index_get(devid, evd->detail, XI_TouchEnd); + if ((i == 0) && (evd->flags & XITouchEmulatingPointer)) + { + _ecore_x_input_touch_index_clear(devid, i); + return; + } +#endif /* #ifdef ECORE_XI2_2 */ + _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 +#ifdef ECORE_XI2_2 + i, 1, 1, +#else + devid, 1, 1, +#endif /* #ifdef ECORE_XI2_2 */ + 1.0, // pressure + 0.0, // angle + evd->event_x, evd->event_y, + evd->root_x, evd->root_y); +#ifdef ECORE_XI2_2 + _ecore_x_input_touch_index_clear(devid, i); +#endif /* #ifdef ECORE_XI2_2 */ + 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 ECORE_XI2_2 + Eina_Inlist *l = _ecore_x_xi2_touch_info_list; + Ecore_X_Touch_Device_Info *info; + info = _ecore_x_input_touch_info_get(dev); + + if (info) + { + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchEnd); + + l = eina_inlist_append(l, (Eina_Inlist *)info); + _ecore_x_xi2_touch_info_list = l; + } +#else +# ifdef XI_TouchUpdate + XISetMask(mask, XI_TouchUpdate); +# endif +# ifdef XI_TouchBegin + XISetMask(mask, XI_TouchBegin); +# endif +# ifdef XI_TouchEnd + XISetMask(mask, XI_TouchEnd); +# endif +#endif /* #ifdef ECORE_XI2_2 */ + + XISelectEvents(_ecore_x_disp, win, &eventmask, 1); + find = EINA_TRUE; + } +#ifdef ECORE_XI2_2 + else if ((atdev) && (atdev->use == XIMasterPointer)) + { + Eina_Inlist *l = _ecore_x_xi2_touch_info_list; + Ecore_X_Touch_Device_Info *info; + info = _ecore_x_input_touch_info_get(dev); + + if (info) + { + XIEventMask eventmask; + unsigned char mask[4] = { 0 }; + + eventmask.deviceid = dev->deviceid; + eventmask.mask_len = sizeof(mask); + eventmask.mask = mask; + + XISetMask(mask, XI_TouchUpdate); + XISetMask(mask, XI_TouchBegin); + XISetMask(mask, XI_TouchEnd); + XISelectEvents(_ecore_x_disp, win, &eventmask, 1); + + l = eina_inlist_append(l, (Eina_Inlist *)info); + _ecore_x_xi2_touch_info_list = l; + + find = EINA_TRUE; + } + } +#endif /* #ifdef ECORE_XI2_2 */ + } + } + + return find; +#else /* ifdef ECORE_XI2 */ + return EINA_FALSE; +#endif /* ifdef ECORE_XI2 */ +} + +EAPI Eina_Bool +ecore_x_input_raw_select(Ecore_X_Window win) +{ +#ifdef ECORE_XI2 + XIEventMask emask; + unsigned char mask[4] = { 0 }; + + if (!_ecore_x_xi2_devs) + return EINA_FALSE; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + emask.deviceid = XIAllMasterDevices; + emask.mask_len = sizeof(mask); + emask.mask = mask; +#ifdef XI_RawButtonPress + XISetMask(emask.mask, XI_RawButtonPress); +#endif +#ifdef XI_RawButtonRelease + XISetMask(emask.mask, XI_RawButtonRelease); +#endif +#ifdef XI_RawMotion + XISetMask(emask.mask, XI_RawMotion); +#endif + + XISelectEvents(_ecore_x_disp, win, &emask, 1); + + return EINA_TRUE; +#else + return EINA_FALSE; +#endif +} + diff --git a/src/lib/ecore_x/xlib/ecore_x_xinerama.c b/src/lib/ecore_x/xlib/ecore_x_xinerama.c index 4c7353d..f49a4d3 100644 --- a/src/lib/ecore_x/xlib/ecore_x_xinerama.c +++ b/src/lib/ecore_x/xlib/ecore_x_xinerama.c @@ -1,9 +1,11 @@ /* - * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 - */ -/* * Xinerama code */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + #include "Ecore.h" #include "ecore_x_private.h" #include "Ecore_X.h" @@ -12,7 +14,7 @@ #ifdef ECORE_XINERAMA static XineramaScreenInfo *_xin_info = NULL; static int _xin_scr_num = 0; -#endif +#endif /* ifdef ECORE_XINERAMA */ EAPI int ecore_x_xinerama_screen_count_get(void) @@ -20,41 +22,70 @@ ecore_x_xinerama_screen_count_get(void) #ifdef ECORE_XINERAMA int event_base, error_base; - if (_xin_info) XFree(_xin_info); + 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; + _xin_info = XineramaQueryScreens(_ecore_x_disp, &_xin_scr_num); + if (_xin_info) + return _xin_scr_num; } -#endif + +#endif /* ifdef ECORE_XINERAMA */ return 0; } -EAPI int -ecore_x_xinerama_screen_geometry_get(int screen, int *x, int *y, int *w, int *h) +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 1; - } - } + 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 - 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 0; + +#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..23bf033 --- /dev/null +++ b/src/modules/immodules/ibus/ibus_imcontext.c @@ -0,0 +1,822 @@ +#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); + if (_focus_im_context == ctx) + _focus_im_context = NULL; +} + +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