tizen 2.4 release accepted/tizen/2.4/mobile/20151029.033132 submit/tizen_2.4/20151028.064158 tizen_2.4_mobile_release
authorjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 06:46:28 +0000 (15:46 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Mon, 26 Oct 2015 06:46:28 +0000 (15:46 +0900)
556 files changed:
.gitignore [new file with mode: 0644]
LICENSE [new file with mode: 0644]
README [new file with mode: 0644]
adaptors/base/conditional-wait.cpp [new file with mode: 0644]
adaptors/base/conditional-wait.h [new file with mode: 0644]
adaptors/base/core-event-interface.h [new file with mode: 0644]
adaptors/base/display-connection.cpp [new file with mode: 0644]
adaptors/base/display-connection.h [new file with mode: 0644]
adaptors/base/environment-options.cpp [new file with mode: 0644]
adaptors/base/environment-options.h [new file with mode: 0644]
adaptors/base/environment-variables.h [new file with mode: 0644]
adaptors/base/file.list [new file with mode: 0644]
adaptors/base/frame-time.cpp [new file with mode: 0644]
adaptors/base/frame-time.h [new file with mode: 0644]
adaptors/base/interfaces/adaptor-internal-services.h [new file with mode: 0644]
adaptors/base/interfaces/egl-factory-interface.h [new file with mode: 0644]
adaptors/base/interfaces/performance-interface.h [new file with mode: 0644]
adaptors/base/interfaces/socket-factory-interface.h [new file with mode: 0644]
adaptors/base/interfaces/socket-interface.h [new file with mode: 0644]
adaptors/base/interfaces/timer-interface.h [new file with mode: 0644]
adaptors/base/interfaces/trace-interface.h [new file with mode: 0644]
adaptors/base/interfaces/vsync-monitor-interface.h [new file with mode: 0644]
adaptors/base/interfaces/window-event-interface.h [new file with mode: 0644]
adaptors/base/lifecycle-observer.h [new file with mode: 0644]
adaptors/base/performance-logging/frame-time-stamp.cpp [new file with mode: 0644]
adaptors/base/performance-logging/frame-time-stamp.h [new file with mode: 0644]
adaptors/base/performance-logging/frame-time-stats.cpp [new file with mode: 0644]
adaptors/base/performance-logging/frame-time-stats.h [new file with mode: 0644]
adaptors/base/performance-logging/networking/client-send-data-interface.h [new file with mode: 0644]
adaptors/base/performance-logging/networking/event/automation.cpp [new file with mode: 0644]
adaptors/base/performance-logging/networking/event/automation.h [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-client.cpp [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-client.h [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-protocol.cpp [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-protocol.h [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-server.cpp [new file with mode: 0644]
adaptors/base/performance-logging/networking/network-performance-server.h [new file with mode: 0644]
adaptors/base/performance-logging/performance-interface-factory.cpp [new file with mode: 0644]
adaptors/base/performance-logging/performance-interface-factory.h [new file with mode: 0644]
adaptors/base/performance-logging/performance-marker.cpp [new file with mode: 0644]
adaptors/base/performance-logging/performance-marker.h [new file with mode: 0644]
adaptors/base/performance-logging/performance-server.cpp [new file with mode: 0644]
adaptors/base/performance-logging/performance-server.h [new file with mode: 0644]
adaptors/base/performance-logging/statistics/stat-context-log-interface.h [new file with mode: 0644]
adaptors/base/performance-logging/statistics/stat-context-manager.cpp [new file with mode: 0644]
adaptors/base/performance-logging/statistics/stat-context-manager.h [new file with mode: 0644]
adaptors/base/performance-logging/statistics/stat-context.cpp [new file with mode: 0644]
adaptors/base/performance-logging/statistics/stat-context.h [new file with mode: 0644]
adaptors/base/render-thread.cpp [new file with mode: 0644]
adaptors/base/render-thread.h [new file with mode: 0644]
adaptors/base/thread-controller.cpp [new file with mode: 0644]
adaptors/base/thread-controller.h [new file with mode: 0644]
adaptors/base/thread-synchronization-debug.h [new file with mode: 0644]
adaptors/base/thread-synchronization.cpp [new file with mode: 0644]
adaptors/base/thread-synchronization.h [new file with mode: 0644]
adaptors/base/update-thread.cpp [new file with mode: 0644]
adaptors/base/update-thread.h [new file with mode: 0644]
adaptors/base/vsync-notifier.cpp [new file with mode: 0644]
adaptors/base/vsync-notifier.h [new file with mode: 0644]
adaptors/common/abort-handler.cpp [new file with mode: 0644]
adaptors/common/abort-handler.h [new file with mode: 0644]
adaptors/common/accessibility-adaptor-impl.h [new file with mode: 0644]
adaptors/common/accessibility-gesture-detector.cpp [new file with mode: 0644]
adaptors/common/accessibility-gesture-detector.h [new file with mode: 0644]
adaptors/common/adaptor-impl.cpp [new file with mode: 0644]
adaptors/common/adaptor-impl.h [new file with mode: 0644]
adaptors/common/adaptor.cpp [new file with mode: 0644]
adaptors/common/application-impl.cpp [new file with mode: 0644]
adaptors/common/application-impl.h [new file with mode: 0644]
adaptors/common/bitmap-loader-impl.cpp [new file with mode: 0644]
adaptors/common/bitmap-loader-impl.h [new file with mode: 0644]
adaptors/common/callback-manager.h [new file with mode: 0644]
adaptors/common/clipboard-event-notifier-impl.cpp [new file with mode: 0644]
adaptors/common/clipboard-event-notifier-impl.h [new file with mode: 0644]
adaptors/common/color-controller-impl.cpp [new file with mode: 0644]
adaptors/common/color-controller-impl.h [new file with mode: 0644]
adaptors/common/command-line-options.cpp [new file with mode: 0644]
adaptors/common/command-line-options.h [new file with mode: 0644]
adaptors/common/damage-observer.h [new file with mode: 0644]
adaptors/common/drag-and-drop-detector-impl.cpp [new file with mode: 0644]
adaptors/common/drag-and-drop-detector-impl.h [new file with mode: 0644]
adaptors/common/event-loop/ecore/ecore-callback-manager.cpp [new file with mode: 0644]
adaptors/common/event-loop/ecore/ecore-callback-manager.h [new file with mode: 0644]
adaptors/common/event-loop/ecore/ecore-file-descriptor-monitor.cpp [new file with mode: 0644]
adaptors/common/event-loop/ecore/ecore-timer-impl.cpp [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-callback-manager.h [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp [new file with mode: 0644]
adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp [new file with mode: 0644]
adaptors/common/events/event-handler.h [new file with mode: 0644]
adaptors/common/events/gesture-detector.h [new file with mode: 0644]
adaptors/common/events/gesture-manager.cpp [new file with mode: 0644]
adaptors/common/events/gesture-manager.h [new file with mode: 0644]
adaptors/common/events/long-press-gesture-detector.cpp [new file with mode: 0644]
adaptors/common/events/long-press-gesture-detector.h [new file with mode: 0644]
adaptors/common/events/pan-gesture-detector-base.cpp [new file with mode: 0644]
adaptors/common/events/pan-gesture-detector-base.h [new file with mode: 0644]
adaptors/common/events/pan-gesture-detector.cpp [new file with mode: 0644]
adaptors/common/events/pan-gesture-detector.h [new file with mode: 0644]
adaptors/common/events/pinch-gesture-detector.cpp [new file with mode: 0644]
adaptors/common/events/pinch-gesture-detector.h [new file with mode: 0644]
adaptors/common/events/tap-gesture-detector.cpp [new file with mode: 0644]
adaptors/common/events/tap-gesture-detector.h [new file with mode: 0644]
adaptors/common/feedback-player-impl.cpp [new file with mode: 0644]
adaptors/common/feedback-player-impl.h [new file with mode: 0644]
adaptors/common/feedback/feedback-plugin-proxy.cpp [new file with mode: 0644]
adaptors/common/feedback/feedback-plugin-proxy.h [new file with mode: 0644]
adaptors/common/file-descriptor-monitor.h [new file with mode: 0644]
adaptors/common/file.list [new file with mode: 0644]
adaptors/common/framework.h [new file with mode: 0644]
adaptors/common/gl/egl-factory.cpp [new file with mode: 0644]
adaptors/common/gl/egl-factory.h [new file with mode: 0644]
adaptors/common/gl/egl-image-extensions.cpp [new file with mode: 0644]
adaptors/common/gl/egl-image-extensions.h [new file with mode: 0644]
adaptors/common/gl/egl-implementation.h [new file with mode: 0644]
adaptors/common/gl/egl-sync-implementation.cpp [new file with mode: 0644]
adaptors/common/gl/egl-sync-implementation.h [new file with mode: 0644]
adaptors/common/gl/gl-extensions.cpp [new file with mode: 0644]
adaptors/common/gl/gl-extensions.h [new file with mode: 0644]
adaptors/common/gl/gl-implementation.h [new file with mode: 0644]
adaptors/common/gl/gl-proxy-implementation.cpp [new file with mode: 0644]
adaptors/common/gl/gl-proxy-implementation.h [new file with mode: 0644]
adaptors/common/indicator-buffer.cpp [new file with mode: 0644]
adaptors/common/indicator-buffer.h [new file with mode: 0644]
adaptors/common/indicator-impl.cpp [new file with mode: 0644]
adaptors/common/indicator-impl.h [new file with mode: 0644]
adaptors/common/kernel-trace.cpp [new file with mode: 0644]
adaptors/common/kernel-trace.h [new file with mode: 0644]
adaptors/common/key-impl.cpp [new file with mode: 0644]
adaptors/common/key-impl.h [new file with mode: 0644]
adaptors/common/lifecycle-controller-impl.cpp [new file with mode: 0644]
adaptors/common/lifecycle-controller-impl.h [new file with mode: 0644]
adaptors/common/locale-utils.cpp [new file with mode: 0644]
adaptors/common/locale-utils.h [new file with mode: 0644]
adaptors/common/native-bitmap-buffer-impl.cpp [new file with mode: 0644]
adaptors/common/native-bitmap-buffer-impl.h [new file with mode: 0644]
adaptors/common/networking/socket-factory.cpp [new file with mode: 0644]
adaptors/common/networking/socket-factory.h [new file with mode: 0644]
adaptors/common/networking/socket-impl.cpp [new file with mode: 0644]
adaptors/common/networking/socket-impl.h [new file with mode: 0644]
adaptors/common/object-profiler.cpp [new file with mode: 0644]
adaptors/common/object-profiler.h [new file with mode: 0644]
adaptors/common/orientation-impl.cpp [new file with mode: 0644]
adaptors/common/orientation-impl.h [new file with mode: 0644]
adaptors/common/performance-logger-impl.cpp [new file with mode: 0644]
adaptors/common/performance-logger-impl.h [new file with mode: 0644]
adaptors/common/physical-keyboard-impl.cpp [new file with mode: 0644]
adaptors/common/physical-keyboard-impl.h [new file with mode: 0644]
adaptors/common/rotation-observer.h [new file with mode: 0644]
adaptors/common/server-connection.cpp [new file with mode: 0644]
adaptors/common/server-connection.h [new file with mode: 0644]
adaptors/common/shared-file.cpp [new file with mode: 0644]
adaptors/common/shared-file.h [new file with mode: 0644]
adaptors/common/singleton-service-impl.cpp [new file with mode: 0644]
adaptors/common/singleton-service-impl.h [new file with mode: 0644]
adaptors/common/sound-player-impl.cpp [new file with mode: 0644]
adaptors/common/sound-player-impl.h [new file with mode: 0644]
adaptors/common/style-monitor-impl.cpp [new file with mode: 0644]
adaptors/common/style-monitor-impl.h [new file with mode: 0644]
adaptors/common/system-settings.cpp [new file with mode: 0644]
adaptors/common/system-settings.h [new file with mode: 0644]
adaptors/common/system-trace.cpp [new file with mode: 0644]
adaptors/common/system-trace.h [new file with mode: 0644]
adaptors/common/timer-impl.h [new file with mode: 0644]
adaptors/common/trigger-event-factory.cpp [new file with mode: 0644]
adaptors/common/trigger-event.cpp [new file with mode: 0644]
adaptors/common/trigger-event.h [new file with mode: 0644]
adaptors/common/virtual-keyboard-impl.cpp [new file with mode: 0644]
adaptors/common/virtual-keyboard-impl.h [new file with mode: 0644]
adaptors/common/vsync-monitor.h [new file with mode: 0644]
adaptors/common/window-impl.h [new file with mode: 0644]
adaptors/common/window-visibility-observer.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/accessibility-action-handler.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/accessibility-adaptor.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/accessibility-adaptor.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/accessibility-gesture-handler.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/bitmap-loader.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/bitmap-loader.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/bitmap-saver.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/bitmap-saver.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/clipboard-event-notifier.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/clipboard-event-notifier.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/clipboard.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/clipboard.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/color-controller.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/color-controller.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/drag-and-drop-detector.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/drag-and-drop-detector.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/event-feeder.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/event-feeder.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/feedback-player.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/feedback-player.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/feedback-plugin.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/imf-manager.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/imf-manager.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/lifecycle-controller.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/lifecycle-controller.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/orientation.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/orientation.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/performance-logger.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/performance-logger.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/physical-keyboard.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/physical-keyboard.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/render-surface.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/singleton-service.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/singleton-service.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/sound-player.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/sound-player.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/style-monitor.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/style-monitor.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/tilt-sensor.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/tilt-sensor.h [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/virtual-keyboard.cpp [new file with mode: 0644]
adaptors/devel-api/adaptor-framework/virtual-keyboard.h [new file with mode: 0644]
adaptors/devel-api/file.list [new file with mode: 0644]
adaptors/integration-api/adaptor.h [new file with mode: 0644]
adaptors/integration-api/egl-interface.h [new file with mode: 0644]
adaptors/integration-api/file.list [new file with mode: 0644]
adaptors/integration-api/pixmap-render-surface-factory.h [new file with mode: 0644]
adaptors/integration-api/thread-synchronization-interface.h [new file with mode: 0644]
adaptors/integration-api/trigger-event-factory-interface.h [new file with mode: 0644]
adaptors/integration-api/trigger-event-factory.h [new file with mode: 0644]
adaptors/integration-api/trigger-event-interface.h [new file with mode: 0644]
adaptors/integration-api/wayland/ecore-wl-render-surface.h [new file with mode: 0644]
adaptors/integration-api/wayland/ecore-wl-types.h [new file with mode: 0644]
adaptors/integration-api/wayland/pixmap-render-surface.h [new file with mode: 0644]
adaptors/integration-api/x11/ecore-x-render-surface.h [new file with mode: 0644]
adaptors/integration-api/x11/ecore-x-types.h [new file with mode: 0644]
adaptors/integration-api/x11/pixmap-render-surface.h [new file with mode: 0644]
adaptors/mobile/file.list [new file with mode: 0644]
adaptors/mobile/mobile-color-controller-impl.cpp [new file with mode: 0644]
adaptors/mobile/mobile-system-settings.cpp [new file with mode: 0644]
adaptors/mobile/pixmap-render-surface-factory.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/application-configuration.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/application.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/application.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/input-method.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/key.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/key.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/native-image-source.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/native-image-source.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/style-change.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/timer.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/timer.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/tts-player.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/tts-player.h [new file with mode: 0644]
adaptors/public-api/adaptor-framework/window.cpp [new file with mode: 0644]
adaptors/public-api/adaptor-framework/window.h [new file with mode: 0644]
adaptors/public-api/dali-adaptor-version.cpp [new file with mode: 0644]
adaptors/public-api/dali-adaptor-version.h [new file with mode: 0644]
adaptors/public-api/dali.h [new file with mode: 0644]
adaptors/public-api/file.list [new file with mode: 0644]
adaptors/scripts/dalireslog.sh [new file with mode: 0755]
adaptors/scripts/dalireslog.txt [new file with mode: 0644]
adaptors/scripts/parse.rb [new file with mode: 0755]
adaptors/tizen/accessibility-adaptor-impl-tizen.cpp [new file with mode: 0644]
adaptors/tizen/adaptor-impl-tizen.cpp [new file with mode: 0644]
adaptors/tizen/file.list [new file with mode: 0644]
adaptors/tizen/framework-tizen.cpp [new file with mode: 0644]
adaptors/tizen/key-grab.h [new file with mode: 0644]
adaptors/tizen/tilt-sensor-impl-tizen.cpp [new file with mode: 0644]
adaptors/tizen/tilt-sensor-impl.h [new file with mode: 0644]
adaptors/tizen/tts-player-impl-tizen.cpp [new file with mode: 0644]
adaptors/tizen/tts-player-impl.h [new file with mode: 0644]
adaptors/tizen/vsync-monitor-tizen.cpp [new file with mode: 0644]
adaptors/tv/file.list [new file with mode: 0644]
adaptors/tv/key-mapping-tv.cpp [new file with mode: 0644]
adaptors/tv/tv-color-controller-impl.cpp [new file with mode: 0644]
adaptors/tv/tv-render-surface-factory.cpp [new file with mode: 0644]
adaptors/tv/tv-system-settings.cpp [new file with mode: 0644]
adaptors/ubuntu/accessibility-adaptor-impl-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/accessibility-adaptor-impl.h [new file with mode: 0644]
adaptors/ubuntu/adaptor-impl-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/file.list [new file with mode: 0644]
adaptors/ubuntu/framework-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/key-mapping-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/tilt-sensor-impl-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/tilt-sensor-impl.h [new file with mode: 0644]
adaptors/ubuntu/tts-player-impl-ubuntu.cpp [new file with mode: 0644]
adaptors/ubuntu/tts-player-impl.h [new file with mode: 0644]
adaptors/ubuntu/vsync-monitor-ubuntu.cpp [new file with mode: 0644]
adaptors/wayland/accessibility-adaptor-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/clipboard-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/clipboard-impl.h [new file with mode: 0644]
adaptors/wayland/display-connection-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/display-connection-impl.h [new file with mode: 0644]
adaptors/wayland/ecore-wl-render-surface-factory.cpp [new file with mode: 0644]
adaptors/wayland/ecore-wl-render-surface-factory.h [new file with mode: 0644]
adaptors/wayland/ecore-wl-render-surface.cpp [new file with mode: 0644]
adaptors/wayland/ecore_wl_private.h [new file with mode: 0644]
adaptors/wayland/egl-implementation-wl.cpp [new file with mode: 0644]
adaptors/wayland/event-handler-wl.cpp [new file with mode: 0644]
adaptors/wayland/file.list [new file with mode: 0644]
adaptors/wayland/framework-wl.cpp [new file with mode: 0644]
adaptors/wayland/imf-manager-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/imf-manager-impl.h [new file with mode: 0644]
adaptors/wayland/key-grab-wl.cpp [new file with mode: 0644]
adaptors/wayland/key-mapping-wl.cpp [new file with mode: 0644]
adaptors/wayland/keyrouter-client-protocol.h [new file with mode: 0644]
adaptors/wayland/native-image-source-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/native-image-source-impl.h [new file with mode: 0644]
adaptors/wayland/pixmap-render-surface-wl.cpp [new file with mode: 0644]
adaptors/wayland/server-connection-wl.cpp [new file with mode: 0644]
adaptors/wayland/system-settings-wl.cpp [new file with mode: 0644]
adaptors/wayland/tizen-extension-client-protocol.h [new file with mode: 0644]
adaptors/wayland/tizen-policy-client-protocol.h [new file with mode: 0644]
adaptors/wayland/virtual-keyboard-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/window-impl-wl.cpp [new file with mode: 0644]
adaptors/wayland/window-render-surface-wl.cpp [new file with mode: 0644]
adaptors/wayland/window-render-surface.h [new file with mode: 0644]
adaptors/x11/accessibility-adaptor-impl-x.cpp [new file with mode: 0644]
adaptors/x11/clipboard-impl-x.cpp [new file with mode: 0644]
adaptors/x11/clipboard-impl.h [new file with mode: 0644]
adaptors/x11/display-connection-impl-x.cpp [new file with mode: 0644]
adaptors/x11/display-connection-impl.h [new file with mode: 0644]
adaptors/x11/ecore-x-event-handler.cpp [new file with mode: 0644]
adaptors/x11/ecore-x-render-surface-factory.cpp [new file with mode: 0644]
adaptors/x11/ecore-x-render-surface-factory.h [new file with mode: 0644]
adaptors/x11/ecore-x-render-surface.cpp [new file with mode: 0644]
adaptors/x11/ecore-x-window-interface.cpp [new file with mode: 0644]
adaptors/x11/ecore-x-window-interface.h [new file with mode: 0644]
adaptors/x11/egl-implementation-x.cpp [new file with mode: 0644]
adaptors/x11/file.list [new file with mode: 0644]
adaptors/x11/framework-x.cpp [new file with mode: 0644]
adaptors/x11/imf-manager-impl-x.cpp [new file with mode: 0644]
adaptors/x11/imf-manager-impl.h [new file with mode: 0644]
adaptors/x11/key-grab-x.cpp [new file with mode: 0644]
adaptors/x11/key-mapping-x.cpp [new file with mode: 0644]
adaptors/x11/native-image-source-impl-x.cpp [new file with mode: 0644]
adaptors/x11/native-image-source-impl.h [new file with mode: 0644]
adaptors/x11/pixmap-render-surface-x.cpp [new file with mode: 0644]
adaptors/x11/server-connection-x.cpp [new file with mode: 0644]
adaptors/x11/system-settings-x.cpp [new file with mode: 0644]
adaptors/x11/virtual-keyboard-impl-x.cpp [new file with mode: 0644]
adaptors/x11/window-extensions.cpp [new file with mode: 0644]
adaptors/x11/window-extensions.h [new file with mode: 0644]
adaptors/x11/window-impl-x.cpp [new file with mode: 0644]
adaptors/x11/window-render-surface-x.cpp [new file with mode: 0644]
adaptors/x11/window-render-surface.h [new file with mode: 0644]
adaptors/x11/x-event-handler.cpp [new file with mode: 0644]
adaptors/x11/x-events/debug/x-input2-debug.cpp [new file with mode: 0644]
adaptors/x11/x-events/debug/x-input2-debug.h [new file with mode: 0644]
adaptors/x11/x-events/x-event-manager.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-event-manager.h [new file with mode: 0644]
adaptors/x11/x-events/x-input2-device.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-input2-device.h [new file with mode: 0644]
adaptors/x11/x-events/x-input2.cpp [new file with mode: 0644]
adaptors/x11/x-events/x-input2.h [new file with mode: 0644]
automated-tests/.gitignore [new file with mode: 0644]
automated-tests/.gitignore-with-autogenerated-files [new file with mode: 0644]
automated-tests/.gitignore-without-autogenerated-files [new file with mode: 0644]
automated-tests/CMakeLists.txt [new file with mode: 0644]
automated-tests/README.md [new file with mode: 0644]
automated-tests/build.sh [new file with mode: 0755]
automated-tests/coverage.sh [new file with mode: 0755]
automated-tests/execute.sh [new file with mode: 0755]
automated-tests/images/README.md [new file with mode: 0644]
automated-tests/images/error-bits.gif [new file with mode: 0644]
automated-tests/images/error-bits.gif.buffer [new file with mode: 0644]
automated-tests/images/frac.24.bmp [new file with mode: 0644]
automated-tests/images/frac.jpg [new file with mode: 0644]
automated-tests/images/frac.png [new file with mode: 0644]
automated-tests/images/interlaced.gif [new file with mode: 0644]
automated-tests/images/interlaced.gif.buffer [new file with mode: 0644]
automated-tests/images/pattern.gif [new file with mode: 0644]
automated-tests/images/pattern.gif.buffer [new file with mode: 0644]
automated-tests/images/transparency.gif [new file with mode: 0644]
automated-tests/images/transparency.gif.buffer [new file with mode: 0644]
automated-tests/packaging/core-dali-adaptor-tests.spec [new file with mode: 0644]
automated-tests/packaging/core-dali-platform-abstraction-tests.spec [new file with mode: 0644]
automated-tests/scripts/add_all_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_style.pl [new file with mode: 0755]
automated-tests/scripts/all_smack.rule [new file with mode: 0644]
automated-tests/scripts/autocompletion.sh [new file with mode: 0755]
automated-tests/scripts/init.sh [new file with mode: 0755]
automated-tests/scripts/retriever.sh [new file with mode: 0755]
automated-tests/scripts/summarize.pl [new file with mode: 0755]
automated-tests/scripts/tcbuild.sh [new file with mode: 0755]
automated-tests/scripts/tcheadgen.sh [new file with mode: 0755]
automated-tests/scripts/tcpackageslistsgen.sh [new file with mode: 0755]
automated-tests/scripts/tctestsgen.sh [new file with mode: 0755]
automated-tests/src/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/common/assert.h [new file with mode: 0644]
automated-tests/src/common/testcase.h [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/image-loaders.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/image-loaders.h [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-ConditionalWait.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Application.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Key.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-SingletonService.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Window.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/resource-collector.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/resource-collector.h [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-all-loads.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-some-loads.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-load-completion.cpp [new file with mode: 0644]
automated-tests/style/back_top.png [new file with mode: 0644]
automated-tests/style/blue.jpg [new file with mode: 0644]
automated-tests/style/gray.jpg [new file with mode: 0644]
automated-tests/style/jquery.min.js [new file with mode: 0644]
automated-tests/style/orange.jpg [new file with mode: 0644]
automated-tests/style/popup.js [new file with mode: 0644]
automated-tests/style/red.jpg [new file with mode: 0644]
automated-tests/style/summary.xsl [new file with mode: 0644]
automated-tests/style/testresult.xsl [new file with mode: 0644]
automated-tests/style/tests.css [new file with mode: 0644]
automated-tests/tcbuild [new symlink]
automated-tests/templates/tct-package/README [new file with mode: 0644]
automated-tests/templates/tct-package/inst.sh [new file with mode: 0755]
build/tizen/.gitignore [new file with mode: 0644]
build/tizen/Makefile.am [new file with mode: 0644]
build/tizen/adaptor/Makefile.am [new file with mode: 0644]
build/tizen/adaptor/dali-adaptor-integration.pc.in [new file with mode: 0644]
build/tizen/adaptor/linker-test.cpp [new file with mode: 0644]
build/tizen/configure.ac [new file with mode: 0644]
build/tizen/dali.pc.in [new file with mode: 0644]
build/tizen/plugins/Makefile.am [new file with mode: 0644]
dali-adaptor.manifest [new file with mode: 0644]
doc/dali-adaptor_doc.h [new file with mode: 0644]
packaging/dali-adaptor.spec [new file with mode: 0644]
platform-abstractions/portable/atomics.h [new file with mode: 0644]
platform-abstractions/portable/file-closer.h [new file with mode: 0644]
platform-abstractions/portable/image-operations.cpp [new file with mode: 0644]
platform-abstractions/portable/image-operations.h [new file with mode: 0644]
platform-abstractions/tizen/data-cache/data-compression.cpp [new file with mode: 0644]
platform-abstractions/tizen/data-cache/data-compression.h [new file with mode: 0644]
platform-abstractions/tizen/file.list [new file with mode: 0755]
platform-abstractions/tizen/image-loaders/image-loader-input.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/image-loader.cpp [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/image-loader.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-bmp.cpp [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-bmp.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-gif.cpp [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-gif.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-ico.cpp [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-ico.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-jpeg-turbo.cpp [new file with mode: 0755]
platform-abstractions/tizen/image-loaders/loader-jpeg.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-ktx.cpp [new file with mode: 0755]
platform-abstractions/tizen/image-loaders/loader-ktx.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-png.cpp [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-png.h [new file with mode: 0644]
platform-abstractions/tizen/image-loaders/loader-wbmp.cpp [new file with mode: 0755]
platform-abstractions/tizen/image-loaders/loader-wbmp.h [new file with mode: 0755]
platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.cpp [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/image-encoder.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/network/file-download.cpp [new file with mode: 0755]
platform-abstractions/tizen/resource-loader/network/file-download.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/network/http-utils.cpp [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/network/http-utils.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/platform-capabilities.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-bitmap-requester.cpp [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-bitmap-requester.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-loader.cpp [new file with mode: 0755]
platform-abstractions/tizen/resource-loader/resource-loader.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-loading-client.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-requester-base.cpp [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-requester-base.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-thread-base.cpp [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-thread-base.h [new file with mode: 0644]
platform-abstractions/tizen/resource-loader/resource-thread-image.cpp [new file with mode: 0755]
platform-abstractions/tizen/resource-loader/resource-thread-image.h [new file with mode: 0644]
platform-abstractions/tizen/tizen-logging.cpp [new file with mode: 0644]
platform-abstractions/tizen/tizen-logging.h [new file with mode: 0644]
platform-abstractions/tizen/tizen-platform-abstraction.cpp [new file with mode: 0644]
platform-abstractions/tizen/tizen-platform-abstraction.h [new file with mode: 0644]
plugins/dali-feedback.cpp [new file with mode: 0644]
plugins/dali-feedback.h [new file with mode: 0644]
plugins/file.list [new file with mode: 0644]
plugins/sounds/file.list [new file with mode: 0644]
plugins/sounds/touch.wav [new file with mode: 0644]
text/dali/devel-api/text-abstraction/bidirectional-support.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/bidirectional-support.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-client.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-client.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-list.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-list.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-metrics.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/font-metrics.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/glyph-info.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/glyph-info.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/script.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/script.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/segmentation.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/segmentation.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/shaping.cpp [new file with mode: 0644]
text/dali/devel-api/text-abstraction/shaping.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/text-abstraction-definitions.h [new file with mode: 0644]
text/dali/devel-api/text-abstraction/text-abstraction.h [new file with mode: 0644]
text/dali/internal/libunibreak/AUTHORS [new file with mode: 0644]
text/dali/internal/libunibreak/LICENCE [new file with mode: 0644]
text/dali/internal/libunibreak/README.md [new file with mode: 0644]
text/dali/internal/libunibreak/file.list [new file with mode: 0644]
text/dali/internal/libunibreak/linebreak.c [new file with mode: 0644]
text/dali/internal/libunibreak/linebreak.h [new file with mode: 0644]
text/dali/internal/libunibreak/linebreakdata.c [new file with mode: 0644]
text/dali/internal/libunibreak/linebreakdef.c [new file with mode: 0644]
text/dali/internal/libunibreak/linebreakdef.h [new file with mode: 0644]
text/dali/internal/libunibreak/wordbreak.c [new file with mode: 0644]
text/dali/internal/libunibreak/wordbreak.h [new file with mode: 0644]
text/dali/internal/libunibreak/wordbreakdata.c [new file with mode: 0644]
text/dali/internal/libunibreak/wordbreakdef.h [new file with mode: 0644]
text/dali/internal/text-abstraction/bidirectional-support-impl.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/bidirectional-support-impl.h [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-helper.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-helper.h [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-impl.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-impl.h [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-plugin-impl.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/font-client-plugin-impl.h [new file with mode: 0644]
text/dali/internal/text-abstraction/segmentation-impl.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/segmentation-impl.h [new file with mode: 0644]
text/dali/internal/text-abstraction/shaping-impl.cpp [new file with mode: 0644]
text/dali/internal/text-abstraction/shaping-impl.h [new file with mode: 0644]
text/file.list [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..213f023
--- /dev/null
@@ -0,0 +1,38 @@
+.cproject
+.project
+.settings
+.directory
+Makefile.in
+Makefile
+dali-adaptor.config
+dali-adaptor.creator*
+dali-adaptor.files
+dali-adaptor.includes
+*~
+*.o
+*.o.d
+*.lo
+*.loT
+*.la
+*.so
+*.orig
+*.odt
+*.fodt
+*.test
+*.example
+*.a
+*.apk
+*.ap_
+*.class
+*.classpath
+*.dex
+*.gcno
+*.gcda
+*.gcov
+.deps
+.libs
+*.swp
+tags
+/build/desktop
+/packaging/home*
+
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..dc0510e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,70 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..ceb23a6
--- /dev/null
+++ b/README
@@ -0,0 +1,55 @@
+T.O.C.
+======
+
+ 1.   GBS Builds
+ 1.1. COMMON Profile
+ 1.2. MOBILE Profile
+ 1.3. WEARABLE Profile
+ 2.   Building for Ubuntu desktop
+ 2.1. Minimum Requirements
+ 2.2. Building the Repository
+
+
+
+1. GBS Builds
+=============
+
+1.1. COMMON Profile
+-------------------
+
+ gbs build -A [TARGET_ARCH]
+
+1.2. MOBILE Profile
+-------------------
+
+ gbs build -A [TARGET_ARCH] --spec dali-adaptor-mobile.spec
+
+1.3. WEARABLE Profile
+---------------------
+
+ gbs build -A [TARGET_ARCH] --spec dali-adaptor-wearable.spec
+
+
+
+2. Building for Ubuntu desktop
+==============================
+
+2.1. Minimum Requirements
+------------------------
+
+ - Ubuntu 14.04
+ - Environment created using dali_env script in dali-core repository
+
+2.2. Building the Repository
+----------------------------
+
+To build the repository enter the 'build/tizen' folder:
+
+ cd dali-adaptor/build/tizen
+
+Then run the following commands:
+
+ autoreconf --install
+ ./configure --prefix=$DESKTOP_PREFIX --enable-profile=UBUNTU --enable-gles=20
+ make install -j8
+
diff --git a/adaptors/base/conditional-wait.cpp b/adaptors/base/conditional-wait.cpp
new file mode 100644 (file)
index 0000000..7f90d1c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "conditional-wait.h"
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct ConditionalWait::ConditionalWaitImpl
+{
+  pthread_mutex_t mutex;
+  pthread_cond_t condition;
+  volatile unsigned int count;
+};
+
+ConditionalWait::ConditionalWait()
+: mImpl( new ConditionalWaitImpl )
+{
+  pthread_mutex_init( &mImpl->mutex, NULL );
+  pthread_cond_init( &mImpl->condition, NULL );
+  mImpl->count = 0;
+}
+
+ConditionalWait::~ConditionalWait()
+{
+  pthread_cond_destroy( &mImpl->condition );
+  pthread_mutex_destroy( &mImpl->mutex );
+  delete mImpl;
+}
+
+void ConditionalWait::Notify()
+{
+  // pthread_cond_wait requires a lock to be held
+  pthread_mutex_lock( &mImpl->mutex );
+  volatile unsigned int previousCount = mImpl->count;
+  mImpl->count = 0; // change state before broadcast as that may wake clients immediately
+  // broadcast does nothing if the thread is not waiting but still has a system call overhead
+  // broadcast all threads to continue
+  if( 0 != previousCount )
+  {
+    pthread_cond_broadcast( &mImpl->condition );
+  }
+  pthread_mutex_unlock( &mImpl->mutex );
+}
+
+void ConditionalWait::Wait()
+{
+  // pthread_cond_wait requires a lock to be held
+  pthread_mutex_lock( &mImpl->mutex );
+  ++(mImpl->count);
+  // pthread_cond_wait may wake up without anyone calling Notify
+  do
+  {
+    // wait while condition changes
+    pthread_cond_wait( &mImpl->condition, &mImpl->mutex ); // releases the lock whilst waiting
+  }
+  while( 0 != mImpl->count );
+  // when condition returns the mutex is locked so release the lock
+  pthread_mutex_unlock( &mImpl->mutex );
+}
+
+unsigned int ConditionalWait::GetWaitCount() const
+{
+  return mImpl->count;
+}
+
+ConditionalWait::ScopedLock::ScopedLock( ConditionalWait& wait ) : mWait(wait)
+{
+  pthread_mutex_lock( &wait.mImpl->mutex );
+}
+
+ConditionalWait::ScopedLock::~ScopedLock()
+{
+  ConditionalWait& wait = mWait;
+  pthread_mutex_unlock( &wait.mImpl->mutex );
+}
+
+void ConditionalWait::Wait( const ScopedLock& scope )
+{
+  // Scope must be locked:
+  DALI_ASSERT_DEBUG( &scope.GetLockedWait() == this );
+
+  ++(mImpl->count);
+
+  // pthread_cond_wait may wake up without anyone calling Notify so loop until
+  // count has been reset in a notify:
+  do
+  {
+    // wait while condition changes
+    pthread_cond_wait( &mImpl->condition, &mImpl->mutex ); // releases the lock whilst waiting
+  }
+  while( 0 != mImpl->count );
+
+  // We return with our mutex locked safe in the knowledge that the ScopedLock
+  // passed in will unlock it in the caller.
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/conditional-wait.h b/adaptors/base/conditional-wait.h
new file mode 100644 (file)
index 0000000..f3f6d5a
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef __DALI_INTERNAL_CONDITIONAL_WAIT_H__
+#define __DALI_INTERNAL_CONDITIONAL_WAIT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Helper class to allow conditional waiting and notifications between multiple threads.
+ */
+class ConditionalWait
+{
+public:
+
+  /**
+   * @brief Allows client code to synchronize updates to its own state with the
+   * internal state of a ConditionalWait object.
+   */
+  class ScopedLock
+  {
+  public:
+    /**
+     * Constructor
+     * @brief Will acquire the internal mutex of the ConditionalWait object passed in.
+     * @param[in] wait The ConditionalWait object to lock.
+     */
+    ScopedLock( ConditionalWait& wait );
+
+    /**
+     * Destructor
+     * @brief Will release the internal mutex of the ConditionalWait object passed in.
+     */
+    ~ScopedLock();
+
+    /**
+     * Getter for the ConditionalWait locked for this instance's lifetime.
+     * @return the ConditionalWait object currently locked.
+     */
+    ConditionalWait& GetLockedWait() const { return mWait; }
+
+  private:
+
+    // Not implemented as ScopedLock cannot be copied:
+    ScopedLock( const ScopedLock& );
+    const ScopedLock& operator=( const ScopedLock& );
+
+    ConditionalWait& mWait;
+  };
+
+  /**
+   * @brief Constructor, creates the internal synchronization objects
+   */
+  ConditionalWait();
+
+  /**
+   * @brief Destructor, non-virtual as this is not a base class
+   */
+  ~ConditionalWait();
+
+  /**
+   * @brief Notifies another thread to continue if it is blocked on a wait.
+   *
+   * Can be called from any thread.
+   * Does not block the current thread but may cause a rescheduling of threads.
+   */
+  void Notify();
+
+  /**
+   * @brief Wait for another thread to notify us when the condition is true and we can continue
+   *
+   * Will always block current thread until Notify is called
+   */
+  void Wait();
+
+  /**
+   * @brief Wait for another thread to notify us when the condition is true and we can continue
+   *
+   * Will always block current thread until Notify is called.
+   * Assumes that the ScopedLock object passed in has already locked the internal state of
+   * this object. Releases the lock while waiting and re-acquires it when returning
+   * from the wait.
+   * param[in] scope A preexisting lock on the internal state of this object.
+   * @pre scope must have been passed this ConditionalWait during its construction.
+   */
+  void Wait( const ScopedLock& scope );
+
+  /**
+   * @brief Return the count of threads waiting for this conditional
+   * @return count of waits
+   */
+  unsigned int GetWaitCount() const;
+
+private:
+
+  // Not implemented as ConditionalWait is not copyable
+  ConditionalWait( const ConditionalWait& );
+  const ConditionalWait& operator= ( const ConditionalWait& );
+
+  struct ConditionalWaitImpl;
+  ConditionalWaitImpl* mImpl;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CONDITIONAL_WAIT_H__
diff --git a/adaptors/base/core-event-interface.h b/adaptors/base/core-event-interface.h
new file mode 100644 (file)
index 0000000..7d3ae59
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct Event;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This interface should be used by adaptor components to send events to Core.
+ * This is preferable to using Core directly i.e. so there is a common place for measuring performance.
+ */
+class CoreEventInterface
+{
+public:
+
+  /**
+   * Queue an event with Core.
+   * @param[in] event The new event.
+   */
+  virtual void QueueCoreEvent(const Dali::Integration::Event& event) = 0;
+
+  /**
+   * Process the events queued with QueueEvent().
+   */
+  virtual void ProcessCoreEvents() = 0;
+
+protected:
+
+  /**
+   * Protected virtual destructor
+   */
+  virtual ~CoreEventInterface() {}
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H__
diff --git a/adaptors/base/display-connection.cpp b/adaptors/base/display-connection.cpp
new file mode 100644 (file)
index 0000000..e69ef62
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <base/display-connection.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <display-connection-impl.h>
+#include <egl-interface.h>
+
+namespace Dali
+{
+
+DisplayConnection* DisplayConnection::New()
+{
+  Internal::Adaptor::DisplayConnection* internal(Internal::Adaptor::DisplayConnection::New());
+
+  return new DisplayConnection(internal);
+}
+
+DisplayConnection::DisplayConnection()
+{
+}
+
+DisplayConnection::DisplayConnection(Internal::Adaptor::DisplayConnection* impl)
+: mImpl(impl)
+{
+}
+
+DisplayConnection::~DisplayConnection()
+{
+  if (mImpl)
+  {
+    delete mImpl;
+    mImpl = NULL;
+  }
+}
+
+Any DisplayConnection::GetDisplay()
+{
+  return mImpl->GetDisplay();
+}
+
+void DisplayConnection::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
+{
+  Internal::Adaptor::DisplayConnection::GetDpi(dpiHorizontal, dpiVertical);
+}
+
+void DisplayConnection::ConsumeEvents()
+{
+  mImpl->ConsumeEvents();
+}
+
+bool DisplayConnection::InitializeEgl(EglInterface& egl)
+{
+  return mImpl->InitializeEgl(egl);
+}
+
+}
diff --git a/adaptors/base/display-connection.h b/adaptors/base/display-connection.h
new file mode 100644 (file)
index 0000000..e38cc78
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef __DALI_DISPLAY_CONNECTION_H__
+#define __DALI_DISPLAY_CONNECTION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+class EglInterface;
+
+namespace Internal
+{
+  namespace Adaptor
+  {
+    class DisplayConnection;
+  }
+}
+
+class DisplayConnection
+{
+public:
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+  /**
+   * @brief Create a DisplayConnection handle; this can be initialised with DisplayConnection::New().
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  DisplayConnection();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~DisplayConnection();
+
+  /**
+   * @brief Get display
+   *
+   * @return display
+   */
+  Any GetDisplay();
+
+  /**
+   * @brief Get DPI
+   * @param[out] dpiHorizontal set to the horizontal dpi
+   * @param[out] dpiVertical set to the vertical dpi
+   */
+  static void GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical);
+
+  /**
+   * @brief Consumes any possible events on the queue so that there is no leaking between frames
+   */
+  void ConsumeEvents();
+
+  /**
+   * @brief Initialize EGL display
+   *
+   * @param egl implementation to use for the creation
+   */
+  bool InitializeEgl(EglInterface& egl);
+
+public:
+
+  /**
+   * @brief This constructor is used by DisplayConnection New() methods.
+   *
+   * @param [in] handle A pointer to a newly allocated DisplayConnection resource
+   */
+  explicit DALI_INTERNAL DisplayConnection(Internal::Adaptor::DisplayConnection* impl);
+
+private:
+
+  Internal::Adaptor::DisplayConnection* mImpl;
+};
+
+}
+
+#endif // __DALI_DISPLAY_CONNECTION_H__
diff --git a/adaptors/base/environment-options.cpp b/adaptors/base/environment-options.cpp
new file mode 100644 (file)
index 0000000..44a300e
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "environment-options.h"
+
+// EXTERNAL INCLUDES
+#include <cstdlib>
+#include <dali/integration-api/render-controller.h>
+#include <dali/public-api/math/math-utils.h>
+
+// INTERNAL INCLUDES
+#include <base/environment-variables.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int DEFAULT_STATISTICS_LOG_FREQUENCY = 2;
+
+unsigned int GetIntegerEnvironmentVariable( const char* variable, unsigned int defaultValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  // if the parameter exists convert it to an integer, else return the default value
+  unsigned int intValue = variableParameter ? std::atoi(variableParameter) : defaultValue;
+  return intValue;
+}
+
+bool GetIntegerEnvironmentVariable( const char* variable, int& intValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  if( !variableParameter )
+  {
+    return false;
+  }
+  // if the parameter exists convert it to an integer, else return the default value
+  intValue = std::atoi(variableParameter);
+  return true;
+}
+
+bool GetFloatEnvironmentVariable( const char* variable, float& floatValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  if( !variableParameter )
+  {
+    return false;
+  }
+  // if the parameter exists convert it to an integer, else return the default value
+  floatValue = std::atof(variableParameter);
+  return true;
+}
+
+const char * GetCharEnvironmentVariable( const char * variable )
+{
+  return std::getenv( variable );
+}
+
+} // unnamed namespace
+
+EnvironmentOptions::EnvironmentOptions()
+: mWindowName(),
+  mWindowClassName(),
+  mNetworkControl( 0 ),
+  mFpsFrequency( 0 ),
+  mUpdateStatusFrequency( 0 ),
+  mObjectProfilerInterval( 0 ),
+  mPerformanceStatsLevel( 0 ),
+  mPerformanceStatsFrequency( DEFAULT_STATISTICS_LOG_FREQUENCY ),
+  mPerformanceTimeStampOutput( 0 ),
+  mPanGestureLoggingLevel( 0 ),
+  mPanGesturePredictionMode( -1 ),
+  mPanGesturePredictionAmount( -1 ), ///< only sets value in pan gesture if greater than 0
+  mPanGestureMaxPredictionAmount( -1 ),
+  mPanGestureMinPredictionAmount( -1 ),
+  mPanGesturePredictionAmountAdjustment( -1 ),
+  mPanGestureSmoothingMode( -1 ),
+  mPanGestureSmoothingAmount( -1.0f ),
+  mPanGestureUseActualTimes( -1 ),
+  mPanGestureInterpolationTimeRange( -1 ),
+  mPanGestureScalarOnlyPredictionEnabled( -1 ),
+  mPanGestureTwoPointPredictionEnabled( -1 ),
+  mPanGestureTwoPointInterpolatePastTime( -1 ),
+  mPanGestureTwoPointVelocityBias( -1.0f ),
+  mPanGestureTwoPointAccelerationBias( -1.0f ),
+  mPanGestureMultitapSmoothingRange( -1 ),
+  mPanMinimumDistance( -1 ),
+  mPanMinimumEvents( -1 ),
+  mGlesCallTime( 0 ),
+  mWindowWidth( 0 ),
+  mWindowHeight( 0 )
+{
+  ParseEnvironmentOptions();
+}
+
+EnvironmentOptions::~EnvironmentOptions()
+{
+}
+
+void EnvironmentOptions::SetLogFunction( const Dali::Integration::Log::LogFunction& logFunction )
+{
+  mLogFunction = logFunction;
+}
+
+void EnvironmentOptions::InstallLogFunction() const
+{
+  Dali::Integration::Log::InstallLogFunction( mLogFunction );
+}
+
+void EnvironmentOptions::UnInstallLogFunction() const
+{
+  Dali::Integration::Log::UninstallLogFunction();
+}
+
+unsigned int EnvironmentOptions::GetNetworkControlMode() const
+{
+  return mNetworkControl;
+}
+unsigned int EnvironmentOptions::GetFrameRateLoggingFrequency() const
+{
+  return mFpsFrequency;
+}
+
+unsigned int EnvironmentOptions::GetUpdateStatusLoggingFrequency() const
+{
+  return mUpdateStatusFrequency;
+}
+
+unsigned int EnvironmentOptions::GetObjectProfilerInterval() const
+{
+  return mObjectProfilerInterval;
+}
+
+unsigned int EnvironmentOptions::GetPerformanceStatsLoggingOptions() const
+{
+  return mPerformanceStatsLevel;
+}
+unsigned int EnvironmentOptions::GetPerformanceStatsLoggingFrequency() const
+{
+  return mPerformanceStatsFrequency;
+}
+unsigned int EnvironmentOptions::GetPerformanceTimeStampOutput() const
+{
+  return mPerformanceTimeStampOutput;
+}
+
+unsigned int EnvironmentOptions::GetPanGestureLoggingLevel() const
+{
+  return mPanGestureLoggingLevel;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionMode() const
+{
+  return mPanGesturePredictionMode;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionAmount() const
+{
+  return mPanGesturePredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGestureMaximumPredictionAmount() const
+{
+  return mPanGestureMaxPredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGestureMinimumPredictionAmount() const
+{
+  return mPanGestureMinPredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionAmountAdjustment() const
+{
+  return mPanGesturePredictionAmountAdjustment;
+}
+
+int EnvironmentOptions::GetPanGestureSmoothingMode() const
+{
+  return mPanGestureSmoothingMode;
+}
+
+float EnvironmentOptions::GetPanGestureSmoothingAmount() const
+{
+  return mPanGestureSmoothingAmount;
+}
+
+int EnvironmentOptions::GetPanGestureUseActualTimes() const
+{
+  return mPanGestureUseActualTimes;
+}
+
+int EnvironmentOptions::GetPanGestureInterpolationTimeRange() const
+{
+  return mPanGestureInterpolationTimeRange;
+}
+
+int EnvironmentOptions::GetPanGestureScalarOnlyPredictionEnabled() const
+{
+  return mPanGestureScalarOnlyPredictionEnabled;
+}
+
+int EnvironmentOptions::GetPanGestureTwoPointPredictionEnabled() const
+{
+  return mPanGestureTwoPointPredictionEnabled;
+}
+
+int EnvironmentOptions::GetPanGestureTwoPointInterpolatePastTime() const
+{
+  return mPanGestureTwoPointInterpolatePastTime;
+}
+
+float EnvironmentOptions::GetPanGestureTwoPointVelocityBias() const
+{
+  return mPanGestureTwoPointVelocityBias;
+}
+
+float EnvironmentOptions::GetPanGestureTwoPointAccelerationBias() const
+{
+  return mPanGestureTwoPointAccelerationBias;
+}
+
+int EnvironmentOptions::GetPanGestureMultitapSmoothingRange() const
+{
+  return mPanGestureMultitapSmoothingRange;
+}
+
+int EnvironmentOptions::GetMinimumPanDistance() const
+{
+  return mPanMinimumDistance;
+}
+
+int EnvironmentOptions::GetMinimumPanEvents() const
+{
+  return mPanMinimumEvents;
+}
+
+unsigned int EnvironmentOptions::GetWindowWidth() const
+{
+  return mWindowWidth;
+}
+
+unsigned int EnvironmentOptions::GetWindowHeight() const
+{
+  return mWindowHeight;
+}
+
+int EnvironmentOptions::GetGlesCallTime() const
+{
+  return mGlesCallTime;
+}
+
+const std::string& EnvironmentOptions::GetWindowName() const
+{
+  return mWindowName;
+}
+
+const std::string& EnvironmentOptions::GetWindowClassName() const
+{
+  return mWindowClassName;
+}
+
+bool EnvironmentOptions::PerformanceServerRequired() const
+{
+  return ( ( GetPerformanceStatsLoggingOptions() > 0) ||
+           ( GetPerformanceTimeStampOutput() > 0 ) ||
+           ( GetNetworkControlMode() > 0) );
+}
+
+void EnvironmentOptions::ParseEnvironmentOptions()
+{
+  // get logging options
+  mFpsFrequency = GetIntegerEnvironmentVariable( DALI_ENV_FPS_TRACKING, 0 );
+  mUpdateStatusFrequency = GetIntegerEnvironmentVariable( DALI_ENV_UPDATE_STATUS_INTERVAL, 0 );
+  mObjectProfilerInterval = GetIntegerEnvironmentVariable( DALI_ENV_OBJECT_PROFILER_INTERVAL, 0 );
+  mPerformanceStatsLevel = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PERFORMANCE_STATS, 0 );
+  mPerformanceStatsFrequency = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PERFORMANCE_STATS_FREQUENCY, 0 );
+  mPerformanceTimeStampOutput = GetIntegerEnvironmentVariable( DALI_ENV_PERFORMANCE_TIMESTAMP_OUTPUT, 0 );
+  mNetworkControl = GetIntegerEnvironmentVariable( DALI_ENV_NETWORK_CONTROL, 0 );
+  mPanGestureLoggingLevel = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PAN_GESTURE, 0 );
+
+  int predictionMode;
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_MODE, predictionMode) )
+  {
+    mPanGesturePredictionMode = predictionMode;
+  }
+  int predictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_AMOUNT, predictionAmount) )
+  {
+    if( predictionAmount < 0 )
+    {
+      // do not support times in the past
+      predictionAmount = 0;
+    }
+    mPanGesturePredictionAmount = predictionAmount;
+  }
+  int minPredictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MIN_PREDICTION_AMOUNT, minPredictionAmount) )
+  {
+    if( minPredictionAmount < 0 )
+    {
+      // do not support times in the past
+      minPredictionAmount = 0;
+    }
+    mPanGestureMinPredictionAmount = minPredictionAmount;
+  }
+  int maxPredictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MAX_PREDICTION_AMOUNT, maxPredictionAmount) )
+  {
+    if( minPredictionAmount > -1 && maxPredictionAmount < minPredictionAmount )
+    {
+      // maximum amount should not be smaller than minimum amount
+      maxPredictionAmount = minPredictionAmount;
+    }
+    mPanGestureMaxPredictionAmount = maxPredictionAmount;
+  }
+  int predictionAmountAdjustment(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_AMOUNT_ADJUSTMENT, predictionAmountAdjustment) )
+  {
+    if( predictionAmountAdjustment < 0 )
+    {
+      // negative amount doesn't make sense
+      predictionAmountAdjustment = 0;
+    }
+    mPanGesturePredictionAmountAdjustment = predictionAmountAdjustment;
+  }
+  int smoothingMode;
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_SMOOTHING_MODE, smoothingMode) )
+  {
+    mPanGestureSmoothingMode = smoothingMode;
+  }
+  float smoothingAmount = 1.0f;
+  if( GetFloatEnvironmentVariable(DALI_ENV_PAN_SMOOTHING_AMOUNT, smoothingAmount) )
+  {
+    smoothingAmount = Clamp(smoothingAmount, 0.0f, 1.0f);
+    mPanGestureSmoothingAmount = smoothingAmount;
+  }
+
+  int useActualTimes( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_USE_ACTUAL_TIMES, useActualTimes ) )
+  {
+    mPanGestureUseActualTimes = useActualTimes == 0 ? 0 : 1;
+  }
+
+  int interpolationTimeRange( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_INTERPOLATION_TIME_RANGE, interpolationTimeRange ) )
+  {
+    if( interpolationTimeRange < 0 )
+    {
+      interpolationTimeRange = 0;
+    }
+    mPanGestureInterpolationTimeRange = interpolationTimeRange;
+  }
+
+  int scalarOnlyPredictionEnabled( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_SCALAR_ONLY_PREDICTION_ENABLED, scalarOnlyPredictionEnabled ) )
+  {
+    mPanGestureScalarOnlyPredictionEnabled = scalarOnlyPredictionEnabled == 0 ? 0 : 1;
+  }
+
+  int twoPointPredictionEnabled( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_PREDICTION_ENABLED, twoPointPredictionEnabled ) )
+  {
+    mPanGestureTwoPointPredictionEnabled = twoPointPredictionEnabled == 0 ? 0 : 1;
+  }
+
+  int twoPointPastInterpolateTime( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_PAST_INTERPOLATE_TIME, twoPointPastInterpolateTime ) )
+  {
+    if( twoPointPastInterpolateTime < 0 )
+    {
+      twoPointPastInterpolateTime = 0;
+    }
+    mPanGestureTwoPointInterpolatePastTime = twoPointPastInterpolateTime;
+  }
+
+  float twoPointVelocityBias = -1.0f;
+  if( GetFloatEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_VELOCITY_BIAS, twoPointVelocityBias ) )
+  {
+    twoPointVelocityBias = Clamp( twoPointVelocityBias, 0.0f, 1.0f );
+    mPanGestureTwoPointVelocityBias = twoPointVelocityBias;
+  }
+
+  float twoPointAccelerationBias = -1.0f;
+  if( GetFloatEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_ACCELERATION_BIAS, twoPointAccelerationBias ) )
+  {
+    twoPointAccelerationBias = Clamp( twoPointAccelerationBias, 0.0f, 1.0f );
+    mPanGestureTwoPointAccelerationBias = twoPointAccelerationBias;
+  }
+
+  int multitapSmoothingRange( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_MULTITAP_SMOOTHING_RANGE, multitapSmoothingRange ) )
+  {
+    if( multitapSmoothingRange < 0 )
+    {
+      multitapSmoothingRange = 0;
+    }
+    mPanGestureMultitapSmoothingRange = multitapSmoothingRange;
+  }
+
+  int minimumDistance(-1);
+  if ( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MINIMUM_DISTANCE, minimumDistance ))
+  {
+    mPanMinimumDistance = minimumDistance;
+  }
+
+  int minimumEvents(-1);
+  if ( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MINIMUM_EVENTS, minimumEvents ))
+  {
+    mPanMinimumEvents = minimumEvents;
+  }
+
+  int glesCallTime(0);
+  if ( GetIntegerEnvironmentVariable(DALI_GLES_CALL_TIME, glesCallTime ))
+  {
+    mGlesCallTime = glesCallTime;
+  }
+
+  int windowWidth(0), windowHeight(0);
+  if ( GetIntegerEnvironmentVariable( DALI_WINDOW_WIDTH, windowWidth ) && GetIntegerEnvironmentVariable( DALI_WINDOW_HEIGHT, windowHeight ) )
+  {
+    mWindowWidth = windowWidth;
+    mWindowHeight = windowHeight;
+  }
+
+  const char * windowName = GetCharEnvironmentVariable( DALI_WINDOW_NAME );
+  if ( windowName )
+  {
+    mWindowName = windowName;
+  }
+
+  const char * windowClassName = GetCharEnvironmentVariable( DALI_WINDOW_CLASS_NAME );
+  if ( windowClassName )
+  {
+    mWindowClassName = windowClassName;
+  }
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/adaptors/base/environment-options.h b/adaptors/base/environment-options.h
new file mode 100644 (file)
index 0000000..6e00177
--- /dev/null
@@ -0,0 +1,285 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
+#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * This class provides the environment options which define settings as well as
+ * the ability to install a log function.
+ *
+ */
+class EnvironmentOptions
+{
+
+public:
+
+  /**
+   * Constructor
+   */
+  EnvironmentOptions();
+
+  /**
+   * non-virtual destructor, not intended as a base class
+   */
+  ~EnvironmentOptions();
+
+  /**
+   * @param logFunction logging function
+   */
+  void SetLogFunction( const Dali::Integration::Log::LogFunction& logFunction );
+
+  /**
+   * Install the log function for the current thread.
+   */
+  void InstallLogFunction() const;
+
+  /**
+   * Un-install the log function for the current thread.
+   */
+  void UnInstallLogFunction() const;
+
+  /**
+   * @return whether network control is enabled or not ( 0 = off, 1 = on )
+   */
+  unsigned int GetNetworkControlMode() const;
+
+  /**
+   * @return frequency of how often FPS is logged out (e.g. 0 = off, 2 = every 2 seconds).
+   */
+  unsigned int GetFrameRateLoggingFrequency() const;
+
+  /**
+   * @return frequency of how often Update Status is logged out (e.g. 0 = off, 60 = log every 60 frames = 1 second @ 60FPS).
+   */
+  unsigned int GetUpdateStatusLoggingFrequency() const;
+
+  /**
+   * @return object profiler status interval ( 0 == off )
+   */
+  unsigned int GetObjectProfilerInterval() const;
+
+  /**
+   * @return performance statistics log level ( 0 == off )
+   */
+  unsigned int GetPerformanceStatsLoggingOptions() const;
+
+  /**
+   * @return performance statistics log frequency in seconds
+   */
+  unsigned int GetPerformanceStatsLoggingFrequency() const;
+
+  /**
+   * @return performance time stamp output ( 0 == off)
+   */
+  unsigned int GetPerformanceTimeStampOutput() const;
+
+  /**
+   * @return pan-gesture logging level ( 0 == off )
+   */
+  unsigned int GetPanGestureLoggingLevel() const;
+
+  /**
+   * @return pan-gesture prediction mode ( -1 means not set so no prediction, 0 = no prediction )
+   */
+  int GetPanGesturePredictionMode() const;
+
+  /**
+   * @return pan-gesture prediction amount
+   */
+  int GetPanGesturePredictionAmount() const;
+
+  /**
+   * @return maximum pan-gesture prediction amount
+   */
+  int GetPanGestureMaximumPredictionAmount() const;
+
+  /**
+   * @return minimum pan-gesture prediction amount
+   */
+  int GetPanGestureMinimumPredictionAmount() const;
+
+  /**
+   * @brief Gets the prediction amount to adjust when the pan velocity is changed.
+   *
+   * If the pan velocity is accelerating, the prediction amount will be increased
+   * by the specified amount until it reaches the upper bound. If the pan velocity
+   * is decelerating, the prediction amount will be decreased by the specified
+   * amount until it reaches the lower bound.
+   *
+   * @return pan-gesture prediction amount adjustment
+   */
+  int GetPanGesturePredictionAmountAdjustment() const;
+
+  /**
+   * @return pan-gesture smoothing mode ( -1 means not set so no smoothing, 0 = no smoothing )
+   */
+  int GetPanGestureSmoothingMode() const;
+
+  /**
+   * @return pan-gesture smoothing amount
+   */
+  float GetPanGestureSmoothingAmount() const;
+
+  /**
+   * @return pan-gesture use actual times is true if real gesture and frame times are to be used.
+   */
+  int GetPanGestureUseActualTimes() const;
+
+  /**
+   * @return pan-gesture interpolation time range is the time range (ms) of past points to use (with weights) when interpolating.
+   */
+  int GetPanGestureInterpolationTimeRange() const;
+
+  /**
+   * @return pan-gesture scalar only prediction, when enabled, ignores acceleration.
+   */
+  int GetPanGestureScalarOnlyPredictionEnabled() const;
+
+  /**
+   * @return pan-gesture two point prediction combines two interpolated points to get more steady acceleration and velocity values.
+   */
+  int GetPanGestureTwoPointPredictionEnabled() const;
+
+  /**
+   * @return pan-gesture two point interpolate past time is the time delta (ms) in the past to interpolate the second point.
+   */
+  int GetPanGestureTwoPointInterpolatePastTime() const;
+
+  /**
+   * @return pan-gesture two point velocity bias is the ratio of first and second points to use for velocity.
+   * 0.0f = 100% of first point. 1.0f = 100% of second point.
+   */
+  float GetPanGestureTwoPointVelocityBias() const;
+
+  /**
+   * @return pan-gesture two point acceleration bias is the ratio of first and second points to use for acceleration.
+   * 0.0f = 100% of first point. 1.0f = 100% of second point.
+   */
+  float GetPanGestureTwoPointAccelerationBias() const;
+
+  /**
+   * @return pan-gesture multitap smoothing range is the range in time (ms) of points in the history to smooth the final output against.
+   */
+  int GetPanGestureMultitapSmoothingRange() const;
+
+  /**
+   * @return The minimum distance before a pan can be started (-1 means it's not set)
+   */
+  int GetMinimumPanDistance() const;
+
+  /**
+   * @return The minimum events before a pan can be started (-1 means it's not set)
+   */
+  int GetMinimumPanEvents() const;
+
+  /**
+   * @return The width of the window
+   */
+  unsigned int GetWindowWidth() const;
+
+  /**
+   * @return The height of the window
+   */
+  unsigned int GetWindowHeight() const;
+
+  /**
+   * @brief Get the graphics status time
+   */
+  int GetGlesCallTime() const;
+
+  /**
+   * @return true if performance server is required
+   */
+  bool PerformanceServerRequired() const;
+
+  /**
+   * @return Gets the window name.
+   */
+  const std::string& GetWindowName() const;
+
+  /**
+   * @return Gets the window class.
+   */
+  const std::string& GetWindowClassName() const;
+
+private: // Internal
+
+  /**
+   * Parses the environment options.
+   * Called from the constructor
+   */
+  void ParseEnvironmentOptions();
+
+private: // Data
+
+  std::string mWindowName;                        ///< name of the window
+  std::string mWindowClassName;                   ///< name of the class the window belongs to
+  unsigned int mNetworkControl;                   ///< whether network control is enabled
+  unsigned int mFpsFrequency;                     ///< how often fps is logged out in seconds
+  unsigned int mUpdateStatusFrequency;            ///< how often update status is logged out in frames
+  unsigned int mObjectProfilerInterval;           ///< how often object counts are logged out in seconds
+  unsigned int mPerformanceStatsLevel;            ///< performance statistics logging bitmask
+  unsigned int mPerformanceStatsFrequency;        ///< performance statistics logging frequency (seconds)
+  unsigned int mPerformanceTimeStampOutput;       ///< performance time stamp output ( bitmask)
+  unsigned int mPanGestureLoggingLevel;           ///< pan-gesture log level
+  int mPanGesturePredictionMode;                  ///< prediction mode for pan gestures
+  int mPanGesturePredictionAmount;                ///< prediction amount for pan gestures
+  int mPanGestureMaxPredictionAmount;             ///< maximum prediction amount for pan gestures
+  int mPanGestureMinPredictionAmount;             ///< minimum prediction amount for pan gestures
+  int mPanGesturePredictionAmountAdjustment;      ///< adjustment of prediction amount for pan gestures
+  int mPanGestureSmoothingMode;                   ///< prediction mode for pan gestures
+  float mPanGestureSmoothingAmount;               ///< prediction amount for pan gestures
+  int mPanGestureUseActualTimes;                  ///< Disable to optionally override actual times if they make results worse.
+  int mPanGestureInterpolationTimeRange;          ///< Time into past history (ms) to use points to interpolate the first point.
+  int mPanGestureScalarOnlyPredictionEnabled;     ///< If enabled, prediction is done using velocity alone (no integration or acceleration).
+  int mPanGestureTwoPointPredictionEnabled;       ///< If enabled, a second interpolated point is predicted and combined with the first to get more stable values.
+  int mPanGestureTwoPointInterpolatePastTime;     ///< The target time in the past to generate the second interpolated point.
+  float mPanGestureTwoPointVelocityBias;          ///< The ratio of first and second interpolated points to use for velocity. 0.0f = 100% of first point. 1.0f = 100% of second point.
+  float mPanGestureTwoPointAccelerationBias;      ///< The ratio of first and second interpolated points to use for acceleration. 0.0f = 100% of first point. 1.0f = 100% of second point.
+  int mPanGestureMultitapSmoothingRange;          ///< The range in time (ms) of points in the history to smooth the final output against.
+  int mPanMinimumDistance;                        ///< minimum distance required before pan starts
+  int mPanMinimumEvents;                          ///< minimum events required before pan starts
+  int mGlesCallTime;                              ///< time in seconds between status updates
+  unsigned int mWindowWidth;                      ///< width of the window
+  unsigned int mWindowHeight;                     ///< height of the window
+
+  Dali::Integration::Log::LogFunction mLogFunction;
+
+  // Undefined copy constructor.
+  EnvironmentOptions( const EnvironmentOptions& );
+
+  // Undefined assignment operator.
+  EnvironmentOptions& operator=( const EnvironmentOptions& );
+
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H__
diff --git a/adaptors/base/environment-variables.h b/adaptors/base/environment-variables.h
new file mode 100644 (file)
index 0000000..dad9e25
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
+#define __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * What performance statistics are logged out to dlog
+ * see StatisticsLogOptions in performance-interface.h for values
+ */
+#define DALI_ENV_LOG_PERFORMANCE_STATS "DALI_LOG_PERFORMANCE_STATS"
+
+/**
+ * How frequent in seconds to log out performance statistics
+ */
+#define DALI_ENV_LOG_PERFORMANCE_STATS_FREQUENCY "DALI_LOG_PERFORMANCE_STATS_FREQ"
+
+/**
+ * Where timestamped events for update/render/event and custom events
+ * are output.
+ * see TimeStampOutput in performance-interface.h for values
+ */
+#define DALI_ENV_PERFORMANCE_TIMESTAMP_OUTPUT "DALI_PERFORMANCE_TIMESTAMP_OUTPUT"
+
+/**
+ * Allow control and monitoring of DALi via the network
+ */
+#define DALI_ENV_NETWORK_CONTROL "DALI_NETWORK_CONTROL"
+
+// environment variable for enabling/disabling fps tracking
+#define DALI_ENV_FPS_TRACKING "DALI_FPS_TRACKING"
+
+#define DALI_ENV_UPDATE_STATUS_INTERVAL "DALI_UPDATE_STATUS_INTERVAL"
+
+#define DALI_ENV_OBJECT_PROFILER_INTERVAL "DALI_OBJECT_PROFILER_INTERVAL"
+
+// Pan-Gesture configuration:
+// Prediction Modes 1 & 2:
+#define DALI_ENV_PAN_PREDICTION_MODE                  "DALI_PAN_PREDICTION_MODE"
+#define DALI_ENV_PAN_PREDICTION_AMOUNT                "DALI_PAN_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_SMOOTHING_MODE                   "DALI_PAN_SMOOTHING_MODE"
+
+// Prediction Mode 1:
+#define DALI_ENV_PAN_MAX_PREDICTION_AMOUNT            "DALI_PAN_MAX_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_MIN_PREDICTION_AMOUNT            "DALI_PAN_MIN_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_PREDICTION_AMOUNT_ADJUSTMENT     "DALI_PAN_PREDICTION_AMOUNT_ADJUSTMENT"
+#define DALI_ENV_PAN_SMOOTHING_AMOUNT                 "DALI_PAN_SMOOTHING_AMOUNT"
+
+// Prediction Mode 2:
+#define DALI_ENV_PAN_USE_ACTUAL_TIMES                 "DALI_PAN_USE_ACTUAL_TIMES"
+#define DALI_ENV_PAN_INTERPOLATION_TIME_RANGE         "DALI_PAN_INTERPOLATION_TIME_RANGE"
+#define DALI_ENV_PAN_SCALAR_ONLY_PREDICTION_ENABLED   "DALI_PAN_SCALAR_ONLY_PREDICTION_ENABLED"
+#define DALI_ENV_PAN_TWO_POINT_PREDICTION_ENABLED     "DALI_PAN_TWO_POINT_PREDICTION_ENABLED"
+#define DALI_ENV_PAN_TWO_POINT_PAST_INTERPOLATE_TIME  "DALI_PAN_TWO_POINT_PAST_INTERPOLATE_TIME"
+#define DALI_ENV_PAN_TWO_POINT_VELOCITY_BIAS          "DALI_PAN_TWO_POINT_VELOCITY_BIAS"
+#define DALI_ENV_PAN_TWO_POINT_ACCELERATION_BIAS      "DALI_PAN_TWO_POINT_ACCELERATION_BIAS"
+#define DALI_ENV_PAN_MULTITAP_SMOOTHING_RANGE         "DALI_PAN_MULTITAP_SMOOTHING_RANGE"
+
+// Pan-Gesture miscellaneous:
+#define DALI_ENV_LOG_PAN_GESTURE                      "DALI_LOG_PAN_GESTURE"
+#define DALI_ENV_PAN_MINIMUM_DISTANCE                 "DALI_PAN_MINIMUM_DISTANCE"
+#define DALI_ENV_PAN_MINIMUM_EVENTS                   "DALI_PAN_MINIMUM_EVENTS"
+
+// Others:
+
+#define DALI_GLES_CALL_TIME "DALI_GLES_CALL_TIME"
+
+#define DALI_WINDOW_WIDTH "DALI_WINDOW_WIDTH"
+
+#define DALI_WINDOW_HEIGHT "DALI_WINDOW_HEIGHT"
+
+#define DALI_WINDOW_NAME "DALI_WINDOW_NAME"
+
+#define DALI_WINDOW_CLASS_NAME "DALI_WINDOW_CLASS_NAME"
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H__
diff --git a/adaptors/base/file.list b/adaptors/base/file.list
new file mode 100644 (file)
index 0000000..9108fc0
--- /dev/null
@@ -0,0 +1,26 @@
+# Add local source files here
+
+base_adaptor_src_files = \
+  $(base_adaptor_src_dir)/conditional-wait.cpp \
+  $(base_adaptor_src_dir)/display-connection.cpp \
+  $(base_adaptor_src_dir)/environment-options.cpp \
+  $(base_adaptor_src_dir)/frame-time.cpp \
+  $(base_adaptor_src_dir)/render-thread.cpp \
+  $(base_adaptor_src_dir)/thread-controller.cpp \
+  $(base_adaptor_src_dir)/thread-synchronization.cpp \
+  $(base_adaptor_src_dir)/update-thread.cpp \
+  $(base_adaptor_src_dir)/vsync-notifier.cpp \
+  $(base_adaptor_src_dir)/performance-logging/frame-time-stamp.cpp \
+  $(base_adaptor_src_dir)/performance-logging/frame-time-stats.cpp \
+  $(base_adaptor_src_dir)/performance-logging/performance-marker.cpp \
+  $(base_adaptor_src_dir)/performance-logging/statistics/stat-context.cpp \
+  $(base_adaptor_src_dir)/performance-logging/statistics/stat-context-manager.cpp
+
+base_adaptor_networking_src_files = \
+  $(base_adaptor_src_dir)/performance-logging/networking/network-performance-protocol.cpp \
+  $(base_adaptor_src_dir)/performance-logging/networking/network-performance-client.cpp \
+  $(base_adaptor_src_dir)/performance-logging/networking/network-performance-server.cpp \
+  $(base_adaptor_src_dir)/performance-logging/networking/event/automation.cpp \
+  $(base_adaptor_src_dir)/performance-logging/performance-server.cpp \
+  $(base_adaptor_src_dir)/performance-logging/performance-interface-factory.cpp
+
diff --git a/adaptors/base/frame-time.cpp b/adaptors/base/frame-time.cpp
new file mode 100644 (file)
index 0000000..09108bc
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "frame-time.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+
+namespace Dali
+{
+
+using Integration::PlatformAbstraction;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
+#endif
+
+const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );
+
+const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
+const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );
+const double RECIPROCAL_MICROSECONDS_PER_MILLISECOND( 0.001f );
+const float        MICROSECONDS_TO_SECONDS( 0.000001f );
+
+const unsigned int HISTORY_SIZE(3);
+
+// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
+const unsigned int TRUE = 1u;
+const unsigned int FALSE = 0u;
+} // unnamed namespace
+
+
+FrameTime::FrameTime( PlatformAbstraction& platform )
+: mPlatform( platform ),
+  mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
+  mLastSyncTime( 0u ),
+  mLastSyncTimeAtUpdate( 0u ),
+  mLastSyncFrameNumber( 0u ),
+  mLastUpdateFrameNumber( 0u ),
+  mRunning( TRUE ),
+  mFirstFrame( TRUE ),
+  writePos( 0u ),
+  mExtraUpdatesSinceSync( 0u )
+{
+  // Clear buffer
+  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
+  {
+    mPreviousUpdateFrames[i] = 0;
+  }
+
+  SetLastSyncTime();
+  mLastSyncTimeAtUpdate = mLastSyncTime;
+
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
+}
+
+FrameTime::~FrameTime()
+{
+}
+
+void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
+{
+  mMinimumFrameTimeInterval = interval;
+}
+
+void FrameTime::SetSyncTime( unsigned int frameNumber )
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  // Only set the render time if we are running
+  if ( mRunning )
+  {
+    SetLastSyncTime();
+
+    mLastSyncFrameNumber = frameNumber;
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
+  }
+}
+
+void FrameTime::Suspend()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  mRunning = FALSE;
+
+  // Reset members
+  mLastSyncFrameNumber = 0;
+  mLastUpdateFrameNumber = 0;
+  writePos = 0;
+  mExtraUpdatesSinceSync = 0;
+
+  // Clear buffer
+  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
+  {
+    mPreviousUpdateFrames[i] = 0;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
+}
+
+void FrameTime::Resume()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );
+
+  SetLastSyncTime();   // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
+  mFirstFrame = TRUE;
+
+  mRunning = TRUE;
+}
+
+void FrameTime::Sleep()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );
+
+  // Mimic Suspend behaviour
+  Suspend();
+}
+
+void FrameTime::WakeUp()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );
+
+  SetLastSyncTime();
+  mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
+  mFirstFrame = TRUE;
+  mRunning = TRUE;
+}
+
+void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  if ( mRunning )
+  {
+    const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
+    const uint64_t lastSyncTime( mLastSyncTime );
+    const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );
+
+    float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
+    unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.
+
+    unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
+    lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;
+
+    // We should only evaluate the previous frame values if this is not the first frame.
+    if ( !mFirstFrame )
+    {
+      // Check whether we have had any Syncs since we last did an Update.
+      if ( framesInLastUpdate == 0 )
+      {
+        // We have had another update before a Sync, increment counter.
+        ++mExtraUpdatesSinceSync;
+
+        // This update frame will be rendered mUpdatesSinceSync later.
+        framesTillNextSync += mExtraUpdatesSinceSync;
+        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
+      }
+      else
+      {
+        mExtraUpdatesSinceSync = 0;
+      }
+
+      // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered.
+      if ( framesInLastUpdate > 1 )
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
+        unsigned int average(0);
+        for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
+        {
+          average += mPreviousUpdateFrames[i];
+        }
+        average /= HISTORY_SIZE;
+
+        if ( average > 1 )
+        {
+          // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
+          framesTillNextSync = average;
+        }
+      }
+
+      // Write the number of frames the last update took to the array.
+      mPreviousUpdateFrames[writePos] = framesInLastUpdate;
+      writePos = ( writePos + 1 ) % HISTORY_SIZE;
+    }
+
+    mLastUpdateFrameNumber = lastSyncFrameNumber;
+    mLastSyncTimeAtUpdate = lastSyncTime;
+    mFirstFrame = FALSE;
+
+    // Calculate the time till the next render
+    double preciseTimeTillNextRender = static_cast<double>( minimumFrameTimeInterval * framesTillNextSync );
+
+    // Set the input variables
+    lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
+    double preciseLastSyncTime = static_cast<double>( lastSyncTime );
+
+    lastSyncTimeMilliseconds = static_cast<unsigned int>( preciseLastSyncTime * RECIPROCAL_MICROSECONDS_PER_MILLISECOND );
+    nextSyncTimeMilliseconds = static_cast<unsigned int>( ( preciseLastSyncTime + preciseTimeTillNextRender ) * RECIPROCAL_MICROSECONDS_PER_MILLISECOND );
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                      FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
+  }
+}
+
+inline void FrameTime::SetLastSyncTime()
+{
+  unsigned int seconds( 0u );
+  unsigned int microseconds( 0u );
+
+  mPlatform.GetTimeMicroseconds( seconds, microseconds );
+
+  mLastSyncTime = seconds; // Promote from 32 bit to 64 bit value
+  mLastSyncTime = ( mLastSyncTime * MICROSECONDS_PER_SECOND ) + microseconds;
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/base/frame-time.h b/adaptors/base/frame-time.h
new file mode 100644 (file)
index 0000000..c3cb363
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
+#define __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+#include <dali/devel-api/common/mutex.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class PlatformAbstraction;
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * FrameTime stores the time of the last VSync. It can then be used by the update thread to predict
+ * the current update will be rendered.
+ */
+class FrameTime
+{
+public:
+
+  // Called from Event thread
+
+  /**
+   * Constructor
+   * @param[in]  platform  The platform used to retrieve the current time
+   */
+  FrameTime( Integration::PlatformAbstraction& platform );
+
+  /**
+   * Destructor, non virtual
+   */
+  ~FrameTime();
+
+  /**
+   * Sets the expected minimum frame time interval.
+   * @param[in]  interval  The interval in microseconds.
+   */
+  void SetMinimumFrameTimeInterval( unsigned int interval );
+
+  /**
+   * Suspends the FrameTime object when the application state changes
+   */
+  void Suspend();
+
+  /**
+   * Resumes the FrameTime object when the application state changes
+   */
+  void Resume();
+
+  // Called from Update thread
+
+  /**
+   * Sets the FrameTime object to sleep, i.e. when there are no more updates required.
+   */
+  void Sleep();
+
+  /**
+   * Wakes the FrameTime object from a sleep state.
+   */
+  void WakeUp();
+
+  /**
+   * Predicts when the next render time will occur.
+   *
+   * @param[out]  lastFrameDeltaSeconds      The delta, in seconds (with float precision), between the last two renders.
+   * @param[out]  lastSyncTimeMilliseconds  The time, in milliseconds, of the last Sync.
+   * @param[out]  nextSyncTimeMilliseconds  The estimated time, in milliseconds, at the next Sync.
+   *
+   * @note Should only be called once per tick, from the update thread.
+   */
+  void PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastVSyncTimeMilliseconds, unsigned int& nextVSyncTimeMilliseconds );
+
+  // Called from VSync thread
+
+  /**
+   * Tells the FrameTime object that a Sync has occurred.
+   *
+   * @param[in]  frameNumber  The frame number of the current Sync.
+   *
+   * @note Should only be called from the VSync thread.
+   */
+  void SetSyncTime( unsigned int frameNumber );
+
+private:
+
+  /**
+   * Sets the current time to be the last Vsync time.
+   */
+  inline void SetLastSyncTime();
+
+private:
+
+  Integration::PlatformAbstraction& mPlatform; ///< The platform abstraction.
+
+  unsigned int mMinimumFrameTimeInterval; ///< The minimum frame time interval, set by Adaptor.
+
+  volatile uint64_t mLastSyncTime;                ///< The last Sync time (in microseconds).
+  volatile uint64_t mLastSyncTimeAtUpdate;        ///< The last Sync time at Update (in microseconds).
+
+  unsigned int mLastSyncFrameNumber;     ///< The last Sync frame number
+  unsigned int mLastUpdateFrameNumber;   ///< The last Sync frame number handled in Update.
+
+  // NOTE cannot use bitfields or booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
+  volatile unsigned int mRunning;        ///< The state of the FrameTime object.
+  unsigned int mFirstFrame;              ///< Whether the current update is the first frame (after initialisation, resume or wake up).
+
+  unsigned int mPreviousUpdateFrames[3]; ///< Array holding the number of frames Update took in the last three iterations.
+  unsigned int writePos;                 ///< The current write position in the array.
+
+  unsigned int mExtraUpdatesSinceSync;   ///< The number of extra updates since the last Sync.
+  Dali::Mutex mMutex;                    ///< Mutex to ensure correct access locking.
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_FRAME_TIME_H__
diff --git a/adaptors/base/interfaces/adaptor-internal-services.h b/adaptors/base/interfaces/adaptor-internal-services.h
new file mode 100644 (file)
index 0000000..be085aa
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H__
+#define __DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <trigger-event-interface.h>
+#include <trigger-event-factory-interface.h>
+#include <base/interfaces/egl-factory-interface.h>
+#include <base/interfaces/socket-factory-interface.h>
+#include <base/interfaces/performance-interface.h>
+#include <base/interfaces/vsync-monitor-interface.h>
+#include <base/interfaces/trace-interface.h>
+#include <render-surface.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * A class to contain various interfaces provided by the adaptor which
+ * can be used by the cross platform parts of adaptor.
+ * E.g. any files held in adaptors/base/ directory
+ *
+ */
+class AdaptorInternalServices
+{
+
+public:
+
+  /**
+   * @return core
+   */
+  virtual Dali::Integration::Core& GetCore() = 0;
+
+  /**
+   * @return platform abstraction
+   */
+  virtual Dali::Integration::PlatformAbstraction& GetPlatformAbstractionInterface()  = 0;
+
+  /**
+   * @return gles abstraction
+   */
+  virtual Dali::Integration::GlAbstraction& GetGlesInterface()  = 0;
+
+  /**
+   * @return egl factory
+   */
+  virtual EglFactoryInterface& GetEGLFactoryInterface() const  = 0;
+
+  /**
+   * Used by update-thread to notify core (main-thread) it has messages to process
+   * @return trigger event ProcessCoreEvents
+   */
+  virtual TriggerEventInterface& GetProcessCoreEventsTrigger()  = 0;
+
+  /**
+   * @return trigger event factory interface
+   */
+  virtual TriggerEventFactoryInterface& GetTriggerEventFactoryInterface() = 0;
+
+  /**
+   * @return socket factory interface
+   */
+  virtual SocketFactoryInterface& GetSocketFactoryInterface() = 0;
+
+  /**
+   * @return render surface
+   */
+  virtual RenderSurface* GetRenderSurfaceInterface()  = 0;
+
+  /**
+   * @return vsync monitor interface
+   */
+  virtual VSyncMonitorInterface* GetVSyncMonitorInterface()  = 0;
+
+  /**
+   * @return performance interface
+   */
+  virtual PerformanceInterface* GetPerformanceInterface()  = 0;
+
+  /**
+   * @return interface for logging to the kernel ( e.g. using ftrace )
+   */
+  virtual TraceInterface& GetKernelTraceInterface()  = 0;
+
+  /**
+   * @return system trace interface, e.g. for using Tizen Trace (ttrace) or Android Trace (atrace)
+   */
+  virtual TraceInterface& GetSystemTraceInterface()  = 0;
+
+
+protected:
+
+  /**
+   * constructor
+   */
+  AdaptorInternalServices()
+  {
+  };
+
+  /**
+   * virtual destructor
+   */
+  virtual ~AdaptorInternalServices()
+  {
+  };
+
+  // Undefined copy constructor.
+  AdaptorInternalServices( const AdaptorInternalServices& );
+
+  // Undefined assignment operator.
+  AdaptorInternalServices& operator=( const AdaptorInternalServices& );
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H__
diff --git a/adaptors/base/interfaces/egl-factory-interface.h b/adaptors/base/interfaces/egl-factory-interface.h
new file mode 100644 (file)
index 0000000..42a6029
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+class EglInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Factory interface for creating EGL implementation
+ */
+class EglFactoryInterface
+{
+public:
+  /**
+   * Create an EGL implementation
+   * @return An implementation of the EGL interface
+   */
+  virtual EglInterface* Create() = 0;
+
+  /**
+   * Destroy the EGL implementation
+   */
+  virtual void Destroy() = 0;
+
+protected:
+  /**
+   * Virtual protected destructor - no deletion through this interface
+   */
+  virtual ~EglFactoryInterface() {};
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_H__
diff --git a/adaptors/base/interfaces/performance-interface.h b/adaptors/base/interfaces/performance-interface.h
new file mode 100644 (file)
index 0000000..0732d10
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef __DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract Performance Interface.
+ * Used by the Adaptor to store performance metrics.
+ *
+ */
+class PerformanceInterface
+{
+public:
+
+  typedef unsigned short ContextId;   ///< Type to represent a context ID
+
+  /**
+   * bitmask of statistics logging options.
+   * Used for output data like min/max/average time spent in event, update,render and custom tasks.
+   * E.g.
+   * Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+   * Update, min 0.29 ms, max 0.91 ms, total (0.5 secs), avg 0.68 ms, std dev 0.15 ms
+   * Render, min 0.33 ms, max 0.97 ms, total (0.6 secs), avg 0.73 ms, std dev 0.17 ms
+   * TableViewInit, min 76.55 ms, max 76.55 ms, total (0.1 secs), avg 76.55 ms, std dev 0.00 ms
+   */
+  enum StatisticsLogOptions
+  {
+    DISABLED             = 0,
+    LOG_EVERYTHING       = 1 << 0, ///< Bit 0 (1), log all statistics to the DALi log
+    LOG_UPDATE_RENDER    = 1 << 1, ///< Bit 1 (2), log update and render statistics to the DALi log
+    LOG_EVENT_PROCESS    = 1 << 2, ///< Bit 2 (4), log event task statistics to the DALi log
+    LOG_CUSTOM_MARKERS   = 1 << 3, ///< Bit 3 (8), log custom marker statistics to the DALi log
+  };
+
+  /**
+   * bitmask of time stamp output options.
+   * E.g. DALI_PERFORMANCE_TIMESTAMP_OUTPUT = 1 dali-demo
+   * Used for logging out time stamped markers for detailed analysis (see MarkerType, for the markers logged)
+   * Typical output would look like:
+   *   379.059025 (seconds), V_SYNC
+   *   379.059066 (seconds), UPDATE_START
+   *   379.059747 (seconds), UPDATE_END
+   *   379.059820 (seconds), RENDER_START
+   *   379.060708 (seconds), RENDER_END
+   *   379.075795 (seconds), V_SYNC
+   *   379.076444 (seconds), MY_CUSTOM_MARKER_START  ( customer marker using PerformanceLogger public API).
+   *   379.077353 (seconds), MY_CUSTOM_MARKER_END  ( customer marker using PerformanceLogger public API).
+   */
+  enum TimeStampOutput
+  {
+    NO_TIME_STAMP_OUTPUT         = 0,
+    OUTPUT_DALI_LOG              = 1 << 0, ///< Bit 0 (1), log markers to DALi log
+    OUTPUT_KERNEL_TRACE          = 1 << 1, ///< Bit 1 (2), log makers to kernel trace
+    OUTPUT_SYSTEM_TRACE          = 1 << 2, ///< Bit 2 (4), log markers to system trace
+    OUTPUT_NETWORK               = 1 << 3, ///< Bit 3 (8), log markers to network client
+  };
+
+  /**
+   * enum for difference performance markers.
+   * Please modify the name lookup table in performance-interface.cpp
+   * file if adding new markers (the order must match one to one).
+   */
+  enum MarkerType
+  {
+    VSYNC     = 0,        ///< V-Sync
+    UPDATE_START ,        ///< Update start
+    UPDATE_END   ,        ///< Update end
+    RENDER_START ,        ///< Render start
+    RENDER_END   ,        ///< Render end
+    SWAP_START   ,        ///< SwapBuffers Start
+    SWAP_END     ,        ///< SwapBuffers End
+    PROCESS_EVENTS_START, ///< Process events start (e.g. touch event)
+    PROCESS_EVENTS_END,   ///< Process events end
+    PAUSED       ,        ///< Pause start
+    RESUME       ,        ///< Resume start
+    START        ,        ///< The start of custom tracking
+    END                   ///< The end of custom tracking
+  };
+
+  /**
+   * Constructor.
+   */
+  PerformanceInterface() {}
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~PerformanceInterface() {};
+
+  /**
+   * @brief Add a new context with a given name
+   *
+   * @param[in] name The name of the context
+   * @return Return the unique id for this context
+   */
+  virtual ContextId AddContext( const char* name ) = 0;
+
+  /**
+   * @brief Remove a context from use
+   *
+   * @param[in] contextId The ID of the context to remove
+   */
+  virtual void RemoveContext( ContextId contextId ) = 0;
+
+  /**
+   * @brief Add a performance marker
+   * This function can be called from ANY THREAD.
+   * The default context 0 Event/Update/Render is assumed.
+   * @param[in] markerType performance marker type
+   */
+  virtual void AddMarker( MarkerType markerType ) = 0;
+
+  /**
+   * @brief Add a performance marker for a used defined context
+   * This function can be called from ANY THREAD.
+   * @param[in] markerType performance marker type
+   * @param[in] contextId The context of the marker. This must be one generated by AddContext.
+   */
+  virtual void AddMarker( MarkerType markerType, ContextId contextId ) = 0;
+
+  /**
+   * @brief Set the logging level and frequency
+   * @param[in] StatisticsLogOptions  0 = disabled, >0 bitmask of StatisticsLogOptions
+   * @param[in] timeStampOutput 0 = disabled, > 0 bitmask of TimeStampOutput options.
+   * @param[in] logFrequency how often to log out in seconds
+   */
+  virtual void SetLogging( unsigned int statisticsLogOptions, unsigned int timeStampOutput, unsigned int logFrequency) = 0;
+
+  /**
+   * @brief Set the logging frequency for an individual context
+   *
+   * @param[in] logFrequency how often to log out in seconds
+   */
+  virtual void SetLoggingFrequency( unsigned int logFrequency, ContextId contextId ) = 0;
+
+  /**
+   * @brief Set logging on or off for a particular context
+   *
+   * @param[in] enable Enable logging or not
+   * @param[in] contextId The id of the context to log. This must be one generated by AddContext.
+   */
+  virtual void EnableLogging( bool enable, ContextId contextId ) = 0;
+
+private:
+
+  // Undefined copy constructor.
+  PerformanceInterface( const PerformanceInterface& );
+
+  // Undefined assignment operator.
+  PerformanceInterface& operator=( const PerformanceInterface& );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/interfaces/socket-factory-interface.h b/adaptors/base/interfaces/socket-factory-interface.h
new file mode 100644 (file)
index 0000000..fea89cb
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <base/interfaces/socket-interface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief abstract class to create and destroy sockets
+ */
+class SocketFactoryInterface
+{
+public:
+
+  /**
+   * @brief Create a new socket
+   * @param protocol network protocol
+   * @return true on success, false on failure
+   */
+   virtual SocketInterface* NewSocket( SocketInterface::Protocol protocol  ) = 0;
+
+   /**
+    * @brief destroy a socket
+    * @param[in] socket socket to destroy
+    */
+   virtual void DestroySocket( SocketInterface* socket  ) = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+   SocketFactoryInterface( )
+  {
+  }
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~SocketFactoryInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  SocketFactoryInterface( const SocketFactoryInterface& );
+
+  // Undefined assignment operator.
+  SocketFactoryInterface& operator=( const SocketFactoryInterface& );
+
+};
+
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H__
diff --git a/adaptors/base/interfaces/socket-interface.h b/adaptors/base/interfaces/socket-interface.h
new file mode 100644 (file)
index 0000000..e76af50
--- /dev/null
@@ -0,0 +1,198 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdint.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief Abstract socket interface.
+ * The typical usage is:
+ *
+ * @code
+ *
+ * SocketFactory::NewSocket( SocketInterface::TCP );
+ * socket->ReuseAddress( true );
+ * socket->Bind( port );
+ * socket->Listen();
+ *
+ * ret = socket->Select();     // call socket->ExitSelect to break from select from another thread
+ * if ( ret == DATA_AVAILABLE )
+ * {
+ *   socket->Read( ...);
+ * }
+ * socket->Close();
+ *
+ * @endcode
+ *
+ */
+class SocketInterface
+{
+public:
+
+  /**
+   * @brief Protocol type
+   */
+  enum Protocol
+  {
+    TCP,          ///< Reliable, connection oriented
+    UDP,          ///< Connection less, no guarantees of packet delivery, ordering
+  };
+
+  /**
+   * @brief check is a socket is open
+   * @return true if the socket is currently open
+   */
+  virtual bool SocketIsOpen() const = 0;
+
+  /**
+   * @brief CloseSocket
+   * @return true on success, false on failure
+   */
+  virtual bool CloseSocket() = 0;
+
+  /**
+   * @brief Socket bind,  associate a local address with a socket ( normally uses AF_INET + INADDR_ANY)
+   * @param[in] port network port
+   * @return true on success, false on failure
+   */
+  virtual bool Bind( uint16_t port ) = 0;
+
+  /**
+   * @brief Indicate a willingness to accept incoming connection requests
+   * @param[in] backlog maximum length of the queue of pending connections.
+   * @return true on success, false on failure
+   */
+  virtual bool Listen( int blacklog) = 0;
+
+  /**
+   * @brief Wait for connection request and make connection
+   * @return new client socket
+   */
+  virtual SocketInterface* Accept() const = 0;
+
+  /**
+   * @brief Select return values
+   */
+  enum SelectReturn
+  {
+    DATA_AVAILABLE,   ///< Data is available to read
+    QUIT,             ///< ExitSelect() has been called on the socket
+    ERROR             ///< Socket error
+  };
+
+  /**
+   * @brief Waits for an event to occur (data available / error)
+   * Returns when
+   * - data has been sent to the socket
+   * - client has closed the connection ( Read will return 0 bytes)
+   * - ExitSelect has been called (returns QUIT)
+   * - There is an error (returns ERROR)
+   * @return DATA_AVAILABLE if data is available
+   */
+  virtual SelectReturn Select() = 0;
+
+  /**
+   * @brief To be called from a separate thread to break out of select
+   */
+  virtual void ExitSelect() = 0;
+
+  /**
+   * @brief Read data from the socket
+   * @param[out] buffer data
+   * @param[in] bufferSizeInBytes buffer size in bytes
+   * @param[out] bytesRead number of bytes read
+   * @return true on success, false on failure
+   */
+  virtual bool Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead  ) = 0;
+
+  /**
+   * @brief Send data to the socket
+   * @param[in] buffer data to write
+   * @param[in] bufferSizeInBytes buffer size in write
+   * @return true on success, false on failure
+   */
+  virtual bool Write( const void* buffer, unsigned int bufferSizeInBytes ) = 0;
+
+  //
+  // Common socket options. Please add more as required.
+  // These should be wrappers around the setsockopt API
+
+  /**
+   * @brief Whether the SO_REUSEADDR is enabled or not.
+   * @param[in] reuse flag.
+   * @return true on success, false on failure
+   */
+  virtual bool ReuseAddress( bool reUse ) = 0;
+
+  /**
+   * @brief Socket buffer type
+   */
+  enum BufferType
+  {
+    SEND_BUFFER,        ///< (SO_SNDBUF) Send buffer size
+    RECIEVE_BUFFER      ///< (SO_RCVBUF) Size of buffer allocated to hold data arriving to the socket
+  };
+
+  /**
+   * @brief Set the send and recieve buffer sizes ( SO_SNDBUF, SO_RCVBUF )
+   * @param[in] type buffer type
+   * @param[in] size buffer size
+   * @return true on success, false on failure
+   */
+  virtual bool SetBufferSize( BufferType type, unsigned int size ) = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  SocketInterface( )
+  {
+  }
+
+  /**
+   * @brief virtual destructor
+   */
+  virtual ~SocketInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  SocketInterface( const SocketInterface& );
+
+  // Undefined assignment operator.
+  SocketInterface& operator=( const SocketInterface& );
+
+};
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H__
diff --git a/adaptors/base/interfaces/timer-interface.h b/adaptors/base/interfaces/timer-interface.h
new file mode 100644 (file)
index 0000000..f2b1462
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Interface for a timer class
+ */
+class TimerInterface
+{
+public:
+  /**
+   * @copydoc Dali::Timer::Start()
+   */
+  virtual void Start() = 0;
+
+  /**
+   * @copydoc Dali::Timer::Stop()
+   */
+  virtual void Stop() = 0;
+
+  /**
+   * @copydoc Dali::Timer::SetInterval()
+   */
+  virtual void SetInterval( unsigned int intervalInMilliseconds ) = 0;
+
+  /**
+   * @copydoc Dali::Timer::GetInterval()
+   */
+  virtual unsigned int GetInterval() const = 0;
+
+  /**
+   * @copydoc Dali::Timer::IsRunning()
+   */
+  virtual bool IsRunning() const = 0;
+
+protected:
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~TimerInterface() { }
+};
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H__
diff --git a/adaptors/base/interfaces/trace-interface.h b/adaptors/base/interfaces/trace-interface.h
new file mode 100644 (file)
index 0000000..21cd38a
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __DALI_INTERNAL_BASE_TRACE_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_TRACE_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/performance-marker.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract Tracing Interface.
+ * Used to log trace messages.
+ * E.g. On Linux this may use ftrace
+ *
+ */
+class TraceInterface
+{
+
+public:
+
+  /**
+   * Write a trace message
+   * @param marker performance marker
+   * @param traceMessage trace message
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage ) = 0;
+
+protected:
+
+  /**
+   * Constructor
+   */
+  TraceInterface()
+  {
+  }
+
+  /**
+   * virtual destructor
+   */
+  virtual ~TraceInterface()
+  {
+  }
+
+  // Undefined copy constructor.
+  TraceInterface( const TraceInterface& );
+
+  // Undefined assignment operator.
+  TraceInterface& operator=( const TraceInterface& );
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/interfaces/vsync-monitor-interface.h b/adaptors/base/interfaces/vsync-monitor-interface.h
new file mode 100644 (file)
index 0000000..2fc1145
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef __DALI_INTERNAL_BASE_VSYNC_MONITOR_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_VSYNC_MONITOR_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Interface for monitoring VSync
+ * Implementations must provide a DoSync method
+ */
+class VSyncMonitorInterface
+{
+public:
+
+  /**
+   * Initialize the vsync monitor.
+   */
+  virtual void Initialize() = 0;
+
+  /**
+   * Terminate the vsync monitor
+   */
+  virtual void Terminate() = 0;
+
+  /**
+   * Checks if hardware sync is available and enabled
+   * @return true if hardware sync is available and enabled
+   */
+  virtual bool UseHardware() = 0;
+
+  /**
+   * Wait for vertical blank sync.
+   * @param[out] frameNumber  The current sequence number for this vsync (increments by one for each vsync)
+   * @param[out] seconds      The timestamp (seconds) when the vsync occured
+   * @param[out] microseconds The timestamp (microseconds) when the vsync occured
+   * @return true if a valid sync was detected, false on error
+   */
+  virtual bool DoSync( unsigned int& frameNumber, unsigned int& seconds, unsigned int& microseconds ) = 0;
+
+protected:
+
+  /**
+   * Virtual protected destructor - no deletion through this interface
+   */
+  virtual ~VSyncMonitorInterface() {}
+
+}; // class VSyncMonitorInterface
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_BASE_VSYNC_MONITOR_INTERFACE_H__
diff --git a/adaptors/base/interfaces/window-event-interface.h b/adaptors/base/interfaces/window-event-interface.h
new file mode 100644 (file)
index 0000000..b689d58
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
+#define __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Abstract interface for handling DALi events received from the native window system
+ *
+ */
+class WindowEventInterface
+{
+
+public:
+
+  /**
+   * @brief Touch Event callback
+   * @param[in] point touch point
+   * @param[in] timeStamp time stamp
+   */
+  virtual void TouchEvent( Dali::TouchPoint& point, unsigned long timeStamp ) = 0;
+
+  /**
+   * @brief Key Event callback
+   * @param[in] keyEvent key event
+   */
+  virtual void KeyEvent( Dali::KeyEvent& keyEvent ) = 0;
+
+  /**
+   * @brief Wheel Event callback
+   * @param[in] wheelEvent wheel event
+   */
+  virtual void WheelEvent( Dali::WheelEvent& wheelEvent ) = 0;
+
+  /**
+   * @brief Window damage callback
+   * @param[in] damageArea Window damage area
+   */
+  virtual void DamageEvent( Dali::Rect<int>& damageArea ) = 0;
+
+  /**
+   * @brief Window Focused
+   */
+  virtual void WindowFocusIn() = 0;
+
+  /**
+   * @brief Window lost focus
+   */
+  virtual void WindowFocusOut() = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  WindowEventInterface()
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~WindowEventInterface()
+  {
+  }
+
+  // Undefined copy constructor.
+  WindowEventInterface( const WindowEventInterface& );
+
+  // Undefined assignment operator.
+  WindowEventInterface& operator=( const WindowEventInterface& );
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H__
diff --git a/adaptors/base/lifecycle-observer.h b/adaptors/base/lifecycle-observer.h
new file mode 100644 (file)
index 0000000..a17ad10
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef __DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H__
+#define __DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Adaptor life cycle observer
+ */
+class LifeCycleObserver
+{
+public:
+  /**
+   * Called when the adaptor has started.
+   */
+  virtual void OnStart() = 0;
+
+  /**
+   * Called when the adaptor is about to pause.
+   */
+  virtual void OnPause() = 0;
+
+  /**
+   * Called when the adaptor is about to resume.
+   */
+  virtual void OnResume() = 0;
+
+  /**
+   * Called when the adaptor is about to stop.
+   */
+  virtual void OnStop() = 0;
+
+  /**
+   * Called when the adaptor is about to be destroyed.
+   */
+  virtual void OnDestroy() = 0;
+
+protected:
+
+  /**
+   * Constructor
+   */
+  LifeCycleObserver()
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~LifeCycleObserver()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  LifeCycleObserver( const LifeCycleObserver& );
+
+  // Undefined assignment operator.
+  LifeCycleObserver& operator=( const LifeCycleObserver& );
+
+};
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H__
diff --git a/adaptors/base/performance-logging/frame-time-stamp.cpp b/adaptors/base/performance-logging/frame-time-stamp.cpp
new file mode 100644 (file)
index 0000000..4fe539d
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "frame-time-stamp.h"
+
+namespace
+{
+const unsigned int MICROSECONDS_PER_SECOND = 1000000; ///< 1000000 microseconds per second
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+FrameTimeStamp::FrameTimeStamp()
+: frame(0),
+  seconds(0),
+  microseconds(0),
+  bufferIndex(0)
+{
+}
+
+FrameTimeStamp::FrameTimeStamp(unsigned int frame,
+                               unsigned int seconds,
+                               unsigned int microseconds,
+                               unsigned int bufferIndex)
+: frame( frame ),
+  seconds( seconds ),
+  microseconds( microseconds ),
+  bufferIndex( bufferIndex )
+{
+}
+
+FrameTimeStamp::FrameTimeStamp(unsigned int bufferIndex )
+: frame( 0 ),
+  seconds(  0 ),
+  microseconds( 0 ),
+  bufferIndex( bufferIndex )
+{
+}
+
+unsigned int FrameTimeStamp::MicrosecondDiff( const FrameTimeStamp& start,const FrameTimeStamp& end )
+{
+  int microDiff = end.microseconds - start.microseconds;
+  unsigned int secDiff = ( end.seconds - start.seconds ) * MICROSECONDS_PER_SECOND;
+  return ( microDiff + secDiff);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/adaptors/base/performance-logging/frame-time-stamp.h b/adaptors/base/performance-logging/frame-time-stamp.h
new file mode 100644 (file)
index 0000000..7d6dcbe
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H__
+#define __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Simple structure to hold information about an event in time
+ * within Dali. For example when rendering started.
+ */
+struct FrameTimeStamp
+{
+
+  static const unsigned int BUFFER_NOT_USED = 2;  ///< no index buffer was used
+
+    /**
+     * Constructor
+     */
+    FrameTimeStamp();
+
+    /**
+     * Constructor
+     * @param frame the frame number
+     * @param second the seconds from a monotonic clock
+     * @param microseconds the microseconds from a monotonic clock
+     * @param bufferIndex  double buffered index used for performing an update / render
+     */
+    FrameTimeStamp( unsigned int frame, unsigned int seconds,unsigned int microseconds, unsigned int bufferIndex = BUFFER_NOT_USED );
+
+    /**
+     * Constructor
+     * @param bufferIndex  double buffered index used for performing an update / render
+     */
+    FrameTimeStamp( unsigned int bufferIndex );
+
+    /**
+     * @param start start time
+     * @param end end time
+     * @return difference in microseconds between two time stamps
+     */
+    static unsigned int MicrosecondDiff( const FrameTimeStamp& start,const FrameTimeStamp& end );
+
+    unsigned int frame;            ///< Frame number ( not always available)
+    unsigned int seconds;          ///< Second time stamp
+    unsigned int microseconds;     ///< Microsecond time stamp
+    unsigned int bufferIndex;      ///< The double buffered index used for performing an update / render
+  };
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H__
+
diff --git a/adaptors/base/performance-logging/frame-time-stats.cpp b/adaptors/base/performance-logging/frame-time-stats.cpp
new file mode 100644 (file)
index 0000000..2bc6028
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// STRUCT HEADER
+#include "frame-time-stats.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float EPSILON = 0.9f; // rolling average = (average * epsilon) + (current * epsilon)
+const float ONE_OVER_MICROSECONDS_TO_SECONDS = 1.f / 1000000.f; ///< microseconds per second
+}
+
+FrameTimeStats::FrameTimeStats()
+: mTotal( 0.f)
+{
+  mSamples.Reserve( 16 );   // Fill out a little to avoid early reallocations
+
+  Reset();
+}
+
+FrameTimeStats::~FrameTimeStats()
+{
+}
+
+void FrameTimeStats::StartTime( const FrameTimeStamp& timeStamp )
+{
+  // check to make sure we don't get 2 start times in a row
+  if( mTimeState != WAITING_FOR_START_TIME )
+  {
+    Reset();
+  }
+
+  mStart = timeStamp;
+  mTimeState = WAITING_FOR_END_TIME;
+}
+
+void FrameTimeStats::EndTime( const FrameTimeStamp& timeStamp )
+{
+  if( mTimeState != WAITING_FOR_END_TIME )
+  {
+    Reset();
+    return;
+  }
+
+  mTimeState = WAITING_FOR_START_TIME;
+  mRunCount++;
+
+  // frame time in seconds
+  unsigned int elapsedTime = FrameTimeStamp::MicrosecondDiff( mStart, timeStamp);
+
+  mSamples.PushBack( elapsedTime );
+
+  // if the min and max times haven't been set, do that now.
+  if( !mMinMaxTimeSet )
+  {
+    mMin = elapsedTime;
+    mMax = elapsedTime;
+    mMinMaxTimeSet = true;
+  }
+  else
+  {
+    if (elapsedTime < mMin)
+    {
+      mMin= elapsedTime;
+    }
+    else if (elapsedTime > mMax)
+    {
+      mMax = elapsedTime;
+    }
+  }
+
+  mTotal += elapsedTime;
+}
+
+void FrameTimeStats::Reset()
+{
+  mTimeState = WAITING_FOR_START_TIME;
+  mMinMaxTimeSet = false;
+  mMin = 0.f;
+  mMax = 0.f;
+  mRunCount = 0;
+  mSamples.Clear();
+}
+
+float FrameTimeStats::GetMaxTime() const
+{
+  return mMax * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+float FrameTimeStats::GetMinTime() const
+{
+  return mMin * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+float FrameTimeStats::GetTotalTime() const
+{
+  return mTotal * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+unsigned int FrameTimeStats::GetRunCount() const
+{
+  return mRunCount;
+}
+
+void FrameTimeStats::CalculateMean( float& meanOut, float& standardDeviationOut ) const
+{
+  if( mSamples.Size() > 0 )
+  {
+    // Mean
+    unsigned int sum = 0;
+    for( Samples::ConstIterator it = mSamples.Begin(), itEnd = mSamples.End(); it != itEnd; ++it )
+    {
+      unsigned int value = *it;
+
+      sum += value;
+    }
+
+    meanOut = static_cast<float>(sum) / mSamples.Size();
+
+    // Variance
+    float variance = 0.0f;
+    for( Samples::ConstIterator it = mSamples.Begin(), itEnd = mSamples.End(); it != itEnd; ++it )
+    {
+      unsigned int value = *it;
+
+      float difference = static_cast<float>(value) - meanOut;
+
+      variance += difference * difference;
+    }
+
+    variance /= mSamples.Size();
+
+    // Standard deviation
+    standardDeviationOut = sqrtf( variance );
+
+    meanOut *= ONE_OVER_MICROSECONDS_TO_SECONDS;
+    standardDeviationOut *= ONE_OVER_MICROSECONDS_TO_SECONDS;
+  }
+  else
+  {
+    meanOut = 0.0f;
+    standardDeviationOut = 0.0f;
+  }
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/frame-time-stats.h b/adaptors/base/performance-logging/frame-time-stats.h
new file mode 100644 (file)
index 0000000..5022f74
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H__
+#define __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/frame-time-stamp.h>
+#include <dali/public-api/common/dali-vector.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Used to get statistics about time stamps over a period of time.
+ * E.g. the min, max, total and average time spent inside two markers,
+ * such as UPDATE_START and UPDATE_END
+ */
+struct FrameTimeStats
+{
+  /**
+   * Constructor
+   */
+  FrameTimeStats();
+
+  /**
+   * Destructor, not intended as a base class
+   */
+  ~FrameTimeStats();
+
+  /**
+   * Timer start time
+   * @param timeStamp time stamp
+   */
+   void StartTime( const FrameTimeStamp& timeStamp );
+
+   /**
+    * Timer end time
+    * @param timeStamp time stamp
+    */
+   void EndTime( const FrameTimeStamp& timeStamp );
+
+   /**
+    * Reset all internal counters / state except total time.
+    */
+   void Reset();
+
+   /**
+    * @return maximum time in seconds
+    */
+   float GetMaxTime() const;
+
+   /**
+    * @return minimum time in seconds
+    */
+   float GetMinTime() const;
+
+   /**
+    * @return total time in second
+    */
+   float GetTotalTime() const;
+
+   /**
+    * Get how many times the timer has been started /stopped
+    */
+   unsigned int GetRunCount() const;
+
+   /**
+    * Calculate the mean and standard deviation
+    *
+    * @param[out] mean The return mean value
+    * @param[out] standardDeviation The return standard deviation value
+    */
+   void CalculateMean( float& meanOut, float& standardDeviationOut ) const;
+
+private:
+
+   /**
+    * internal time state.
+    */
+   enum TimeState
+   {
+     WAITING_FOR_START_TIME,    ///< waiting for start time marker
+     WAITING_FOR_END_TIME       ///< waiting for end time marker
+   };
+
+   typedef Dali::Vector< unsigned int > Samples;
+   Samples mSamples;
+
+   unsigned int mMin;                  ///< current minimum value in microseconds
+   unsigned int mMax;                  ///< current maximum value in microseconds
+   unsigned int mTotal;                ///< current total in in microseconds
+   unsigned int mRunCount;      ///< how many times the timer has been start / stopped
+   FrameTimeStamp mStart;       ///< start time stamp, to calculate the diff
+   TimeState mTimeState:1;      ///< time state
+   bool mMinMaxTimeSet:1;       ///< whether the min-max values have been configured
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H__
+
diff --git a/adaptors/base/performance-logging/networking/client-send-data-interface.h b/adaptors/base/performance-logging/networking/client-send-data-interface.h
new file mode 100644 (file)
index 0000000..905fc41
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief  Abstract interface used to transmit data to a client
+ */
+class ClientSendDataInterface
+{
+public:
+
+  /**
+   * @brief Sends data to the client
+   * @param[in] data pointer to some data
+   * @param[in] bufferSizeInBytes how big the buffer is in bytes
+   * @param[in] clientId unique client id to send the data to
+   */
+  virtual void SendData( const char* const data, unsigned int bufferSizeInBytes, unsigned int clientId ) = 0;
+
+
+protected:
+
+  /**
+   * @brief  Constructor
+   */
+  ClientSendDataInterface()
+  {
+  }
+
+  /**
+   * @brief Virtual Destructor
+   */
+  virtual ~ClientSendDataInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  ClientSendDataInterface( const ClientSendDataInterface& );
+
+  // Undefined assignment operator.
+  ClientSendDataInterface& operator=( const ClientSendDataInterface& );
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H__
diff --git a/adaptors/base/performance-logging/networking/event/automation.cpp b/adaptors/base/performance-logging/networking/event/automation.cpp
new file mode 100644 (file)
index 0000000..d755336
--- /dev/null
@@ -0,0 +1,340 @@
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "automation.h"
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <stdio.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/debug.h>
+
+
+namespace  // un-named namespace
+{
+
+const unsigned int MAX_SET_PROPERTY_STRING_LENGTH = 256; ///< maximum length of a set property command
+
+class JsonPropertyValue
+{
+public:
+  JsonPropertyValue( const std::string& str )
+  {
+    std::size_t strLength = str.length();
+
+    mString.reserve( strLength );
+    for( std::size_t i = 0; i < strLength; ++i )
+    {
+      const char c = str[i];
+      if( (c != '[') && c != ']')
+      {
+        mString.push_back( c );
+      }
+    }
+
+  }
+  std::string GetString() const
+  {
+    return mString;
+  }
+  float GetFloat() const
+  {
+    return atof( mString.c_str() );
+  }
+  int GetInt()
+  {
+    return atoi( mString.c_str() );
+  }
+  bool GetBoolean()
+  {
+    return (GetInt() != 0);
+  }
+
+  Dali::Vector2 GetVector2()
+  {
+    Dali::Vector2 vec2;
+
+    int count = sscanf( mString.c_str(),"%f,%f",&vec2.x,&vec2.y );
+    if( count != 2 )
+    {
+      DALI_LOG_ERROR("Bad format");
+    }
+    return vec2;
+  }
+
+  Dali::Vector3 GetVector3()
+  {
+    Dali::Vector3 vec3;
+
+    int count = sscanf( mString.c_str(),"%f,%f,%f",&vec3.x,&vec3.y,&vec3.z );
+    if( count != 3 )
+    {
+      DALI_LOG_ERROR("Bad format");
+    }
+    return vec3;
+  }
+
+  Dali::Vector4 GetVector4()
+  {
+    Dali::Vector4 vec4;
+
+    int count = sscanf( mString.c_str(),"%f,%f,%f,%f", &vec4.x, &vec4.y, &vec4.z, &vec4.w );
+    if( count != 4 )
+    {
+      DALI_LOG_ERROR("Bad format");
+    }
+    return vec4;
+  }
+
+private:
+  std::string mString;
+
+};
+
+void SetProperty( Dali::Handle handle, int propertyId, JsonPropertyValue& propertyValue )
+{
+  Dali::Property::Type type = handle.GetPropertyType( propertyId );
+  switch( type )
+  {
+  case Dali::Property::FLOAT:
+  {
+    float val = propertyValue.GetFloat();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::INTEGER:
+  {
+    int val = propertyValue.GetInt();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::BOOLEAN:
+  {
+    bool val = propertyValue.GetBoolean();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::STRING:
+  {
+    std::string str = propertyValue.GetString();
+    handle.SetProperty( propertyId, Dali::Property::Value( str ) );
+    break;
+  }
+  case Dali::Property::VECTOR2:
+  {
+    Dali::Vector2 val = propertyValue.GetVector2();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::VECTOR3:
+  {
+    Dali::Vector3 val = propertyValue.GetVector3();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::VECTOR4:
+  {
+    Dali::Vector4 val = propertyValue.GetVector4();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  default:
+  {
+    break;
+  }
+  }
+}
+
+int SetProperties( const std::string& setPropertyMessage )
+{
+  std::istringstream iss( setPropertyMessage );
+  std::string token;
+  getline( iss, token, '|' ); // swallow command name
+  while( getline( iss, token, '|' ) )
+  {
+    std::string actorId, propName, propValue;
+    if( token.compare( "---" ) != 0 )
+    {
+      std::istringstream propss( token );
+      getline( propss, actorId, ';' );
+      getline( propss, propName, ';' );
+      getline( propss, propValue );
+
+      Dali::Actor root = Dali::Stage::GetCurrent().GetRootLayer();
+      int id = atoi( actorId.c_str() );
+      Dali::Actor a = root.FindChildById( id );
+      if( a )
+      {
+        // lookup by name for custom properties
+        int propId = a.GetPropertyIndex( propName );
+        if( propId > 0 )
+        {
+          JsonPropertyValue pv( propValue );
+          SetProperty( a, propId, pv );
+        }
+
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+}; //   un-named namespace
+
+inline std::string Quote( const std::string& in )
+{
+  return (std::string( "\"" ) + in + std::string( "\"" ));
+}
+
+template<class T>
+std::string ToString( T i )
+{
+  std::stringstream ss;
+  std::string s;
+  ss << i;
+  s = ss.str();
+
+  return s;
+}
+
+
+// currently rotations are output in Euler format ( may change)
+void AppendPropertyNameAndValue( Dali::Handle handle, int propertyIndex, std::ostringstream& outputStream)
+{
+  // get the property name and the value as a string
+  std::string propertyName( handle.GetPropertyName( propertyIndex ) );
+  Dali::Property::Value value = handle.GetProperty( propertyIndex );
+
+  // Apply quotes around the property name and the value.. "color", "1.3, 3.4, 2.6"
+  outputStream << "\"" << propertyName << "\"" << ",";
+  outputStream << "\"" << value << "\"";
+
+}
+
+bool ExcludeProperty( int propIndex )
+{
+  return (propIndex == Dali::Actor::Property::NAME    ||
+
+      // all of these are repeat properties of values in vectors....
+      // We don't really need these in the UI
+      propIndex == Dali::Actor::Property::ANCHOR_POINT_X || propIndex == Dali::Actor::Property::ANCHOR_POINT_Y || propIndex == Dali::Actor::Property::ANCHOR_POINT_Z || propIndex == Dali::Actor::Property::PARENT_ORIGIN_X
+      || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Y || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Z || propIndex == Dali::Actor::Property::COLOR_RED || propIndex == Dali::Actor::Property::COLOR_GREEN
+      || propIndex == Dali::Actor::Property::COLOR_BLUE || propIndex == Dali::Actor::Property::COLOR_ALPHA|| propIndex == Dali::Actor::Property::POSITION_X || propIndex == Dali::Actor::Property::POSITION_Y
+      || propIndex == Dali::Actor::Property::POSITION_Z|| propIndex == Dali::Actor::Property::SIZE_WIDTH|| propIndex == Dali::Actor::Property::SIZE_HEIGHT || propIndex == Dali::Actor::Property::SCALE_X || propIndex == Dali::Actor::Property::SCALE_Y
+      || propIndex == Dali::Actor::Property::SCALE_Z || propIndex == Dali::Actor::Property::SIZE_DEPTH);
+}
+
+std::string DumpJson( Dali::Actor actor, int level )
+{
+  // All the information about this actor
+  std::ostringstream msg;
+  msg << "{ " << Quote( "Name" ) << " : " << Quote( actor.GetName() ) << ", " << Quote( "level" ) << " : " << level << ", " << Quote( "id" ) << " : " << actor.GetId() << ", " << Quote( "IsVisible" )
+      << " : " << actor.IsVisible() << ", " << Quote( "IsSensitive" ) << " : " << actor.IsSensitive();
+
+  msg << ", " << Quote( "properties" ) << ": [ ";
+
+  Dali::Property::IndexContainer indices;
+  actor.GetPropertyIndices( indices );
+
+  Dali::Property::IndexContainer::Iterator iter = indices.Begin();
+  int numCustom = 0;
+  for( ; iter != indices.End() ; iter++ )
+  {
+    int i = *iter;
+    if( !ExcludeProperty( i ) )
+    {
+      if( numCustom++ != 0 )
+      {
+        msg << ", ";
+      }
+      msg << "[";
+
+      AppendPropertyNameAndValue( actor, i,msg );
+
+      msg << "]";
+    }
+  }
+  msg << "]";
+  msg << ", " << Quote( "children" ) << " : [ ";
+
+  // Recursively dump all the children as well
+  for( unsigned int i = 0 ; i < actor.GetChildCount() ; ++i )
+  {
+    if( i )
+    {
+      msg << " , ";
+    }
+    msg << DumpJson( actor.GetChildAt( i ), level + 1 );
+  }
+  msg << "] }";
+
+  return msg.str();
+}
+
+std::string GetActorTree()
+{
+  Dali::Actor actor = Dali::Stage::GetCurrent().GetRootLayer();
+  std::string str = DumpJson( actor, 0 );
+  return str;
+}
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Automation
+{
+
+void SetProperty( const std::string& message )
+{
+  // check the set property length is within range
+  if( message.length() > MAX_SET_PROPERTY_STRING_LENGTH )
+  {
+    DALI_LOG_ERROR("SetProperty message length too long, size = %ul\n", message.length());
+    return;
+  }
+
+  SetProperties( message );
+}
+
+void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData )
+{
+  char buf[32];
+  std::string json = GetActorTree();
+  int length = json.length();
+  snprintf( buf, 32, "%d\n", length );
+  std::string header( buf );
+  json = buf + json;
+  sendData->SendData( json.c_str(), json.length(), clientId );
+}
+
+} // namespace Automation
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/networking/event/automation.h b/adaptors/base/performance-logging/networking/event/automation.h
new file mode 100644 (file)
index 0000000..4194f09
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_AUTOMATION_H__
+#define __DALI_INTERNAL_ADAPTOR_AUTOMATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// EXTERNAL INCLUDES
+#include <string>
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/networking/client-send-data-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief The automation functions allow a way to control Dali via a network socket.
+ *
+ * The functions must be called from the event thread only.
+ *
+ * Any functions which require a response to be sent back to the network client
+ * use the ClientSendDataInterface interface.
+
+ * E.g.
+ * Dali network client thread            <---- "dump_scene" from network
+ * Dali main thread       "json data"    ----->   network
+ *
+ */
+namespace Automation
+{
+
+/**
+ * @brief Sets properties on an Actor.
+ * No ClientSendDataInterface required, as no response is sent back
+ * @param[in] message set property message
+ */
+void SetProperty( const std::string& message );
+
+
+/**
+ * @brief Dumps the actor tree to the client
+ * @param[in] clientId unique network client id
+ * @param[in] sendData interface to transmit data to the client
+ */
+void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData );
+
+
+} // namespace Automation
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/performance-logging/networking/network-performance-client.cpp b/adaptors/base/performance-logging/networking/network-performance-client.cpp
new file mode 100644 (file)
index 0000000..27fb07a
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "network-performance-client.h"
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/socket-interface.h>
+#include <base/performance-logging/networking/network-performance-protocol.h>
+#include <base/performance-logging/networking/event/automation.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char UNKNOWN_CMD[]= "Command or parameter invalid, type help for list of commands\n";
+
+
+/**
+ * helper class to store data along with the automation callback.
+ */
+class AutomationCallback: public CallbackBase
+{
+public:
+
+  /**
+   * instead of using templates, or having different callback classes for each callback
+   * we use a command id that decides which static function to call on the Automation class.
+   */
+  enum CommandId
+  {
+    UNKNOWN_COMMAND,
+    SET_PROPERTY,
+    DUMP_SCENE
+  };
+
+  AutomationCallback(  unsigned int clientId, ClientSendDataInterface& sendDataInterface )
+  :CallbackBase( reinterpret_cast< void* >( this ),
+                 NULL, // we get the dispatcher to call function directly
+                 reinterpret_cast< CallbackBase::Dispatcher>( &AutomationCallback::Dispatcher) ),
+  mSendDataInterface( sendDataInterface ),
+  mCommandId( UNKNOWN_COMMAND ),
+  mClientId( clientId )
+  {}
+
+  void AssignSetPropertyCommand( std::string setPropertyCommand )
+  {
+    mCommandId = SET_PROPERTY;
+    mPropertyCommand = setPropertyCommand;
+  }
+  void AssignDumpSceneCommand()
+  {
+     mCommandId = DUMP_SCENE;
+  }
+
+  void RunCallback()
+  {
+    switch( mCommandId )
+    {
+      case SET_PROPERTY:
+      {
+        Automation::SetProperty( mPropertyCommand );
+        break;
+      }
+      case DUMP_SCENE:
+      {
+        Automation::DumpScene( mClientId, &mSendDataInterface);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG( 0 && "Unknown command");
+        break;
+      }
+    }
+  }
+  static void Dispatcher( CallbackBase& base )
+  {
+    AutomationCallback& automationCallback( static_cast< AutomationCallback& >( base) );
+    automationCallback.RunCallback();
+  }
+
+private:
+
+  std::string mPropertyCommand;                   ///< property command
+  ClientSendDataInterface& mSendDataInterface;    ///< Abstract client send data interface
+  CommandId mCommandId;                           ///< command id
+  const unsigned int mClientId;                   ///< client id
+};
+
+} // unnamed namespace
+
+NetworkPerformanceClient::NetworkPerformanceClient(  pthread_t* thread,
+                                                     SocketInterface *socket,
+                                                     unsigned int clientId,
+                                                     TriggerEventFactoryInterface& triggerEventFactory,
+                                                     ClientSendDataInterface& sendDataInterface,
+                                                     SocketFactoryInterface& socketFactory )
+: mThread( thread ),
+  mSocket( socket ),
+  mMarkerBitmask( PerformanceMarker::FILTERING_DISABLED ),
+  mTriggerEventFactory( triggerEventFactory ),
+  mSendDataInterface( sendDataInterface ),
+  mSocketFactoryInterface( socketFactory ),
+  mClientId( clientId ),
+  mConsoleClient(false)
+{
+
+}
+
+NetworkPerformanceClient::~NetworkPerformanceClient()
+{
+  if( mSocket->SocketIsOpen() )
+  {
+    mSocket->CloseSocket();
+  }
+  mSocketFactoryInterface.DestroySocket( mSocket );
+}
+
+unsigned int NetworkPerformanceClient::GetId() const
+{
+  return mClientId;
+}
+
+SocketInterface& NetworkPerformanceClient::GetSocket()
+{
+  return *mSocket;
+}
+
+bool NetworkPerformanceClient::WriteSocket( const void* buffer, unsigned int bufferSizeInBytes )
+{
+  return mSocket->Write( buffer, bufferSizeInBytes );
+}
+
+bool NetworkPerformanceClient::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+  if( ! marker.IsFilterEnabled( mMarkerBitmask ) )
+  {
+    return true;
+  }
+  if( mConsoleClient )
+  {
+    // write out the time stamp
+    char buffer[64];
+    int size = snprintf( buffer, sizeof(buffer),"%d.%06d (seconds), %s\n",
+                                    marker.GetTimeStamp().seconds,
+                                    marker.GetTimeStamp().microseconds,
+                                    description );
+
+   return mSocket->Write( buffer, size );
+
+  }
+
+  // todo serialize the data
+  return false;
+}
+
+void NetworkPerformanceClient::ExitSelect()
+{
+  mSocket->ExitSelect();
+}
+
+pthread_t* NetworkPerformanceClient::GetThread()
+{
+  return mThread;
+}
+
+void NetworkPerformanceClient::ProcessCommand( char* buffer, unsigned int bufferSizeInBytes )
+{
+  // if connected via console, then strip off the carriage return, and switch to console mode
+  if( buffer[ bufferSizeInBytes - 1] == '\n')
+  {
+    buffer[ bufferSizeInBytes - 1] = 0;
+    mConsoleClient = true;
+  }
+  unsigned int param(0);
+  std::string stringParam;
+  PerformanceProtocol::CommandId commandId( PerformanceProtocol::UNKNOWN_COMMAND );
+
+  bool ok =  PerformanceProtocol::GetCommandId( buffer, bufferSizeInBytes, commandId, param, stringParam );
+  if( !ok )
+  {
+    WriteSocket( UNKNOWN_CMD, sizeof(UNKNOWN_CMD) );
+    return;
+  }
+  std::string response;
+
+  switch( commandId )
+  {
+    case PerformanceProtocol::HELP_MESSAGE:
+    {
+      response = PerformanceProtocol::GetHelpMessage();
+      break;
+    }
+
+    case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
+    {
+      mMarkerBitmask  = static_cast<  PerformanceMarker::MarkerFilter >( param );
+      response = "enable time marker ";
+      break;
+    }
+
+    case PerformanceProtocol::DUMP_SCENE_GRAPH:
+    {
+      // this needs to be run on the main thread, use the trigger event....
+      AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+      callback->AssignDumpSceneCommand();
+
+      // create a trigger event that automatically deletes itself after the callback has run in the main thread
+      TriggerEventInterface *interface = mTriggerEventFactory.CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+      // asynchronous call, the call back will be run sometime later on the main thread
+      interface->Trigger();
+      break;
+    }
+
+    case PerformanceProtocol::SET_PROPERTIES:
+    {
+      // this needs to be run on the main thread, use the trigger event....
+      AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+      callback->AssignSetPropertyCommand( stringParam );
+
+      // create a trigger event that automatically deletes itself after the callback has run in the main thread
+      TriggerEventInterface *interface = mTriggerEventFactory.CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+      // asynchronous call, the call back will be run sometime later on the main thread
+      interface->Trigger();
+      break;
+    }
+
+    case PerformanceProtocol::LIST_METRICS_AVAILABLE:
+    case PerformanceProtocol::ENABLE_METRIC:
+    case PerformanceProtocol::DISABLE_METRIC:
+    {
+      response="Metrics currently not supported";
+      break;
+    }
+    default:
+    {
+      response = UNKNOWN_CMD;
+      break;
+    }
+  }
+  if( ! response.empty() )
+  {
+    // add a carriage return for console clients
+    if( mConsoleClient )
+    {
+      response+="\n";
+    }
+    WriteSocket( response.c_str(), response.length()  );
+  }
+}
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/networking/network-performance-client.h b/adaptors/base/performance-logging/networking/network-performance-client.h
new file mode 100644 (file)
index 0000000..d9ea2c9
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_CLIENT_H__
+#define __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_CLIENT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/performance-marker.h>
+#include <trigger-event-factory-interface.h>
+#include <base/performance-logging/networking/client-send-data-interface.h>
+#include <base/interfaces/socket-factory-interface.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *  @brief Network Performance client
+ *
+ *  Every time a client connects to Dali, a NetworkPerformanceClient object is created.
+ *  It is responsible for processing incoming commands, and storing the client state
+ *  (e.g. what performance markers it wants).
+ *
+ *  Certain commands such as dump-scene need to be run on the main Dali event thread.
+ *  To achieve this, a trigger event is used which executes a function on the main thread.
+ *  The sendDataInterface is then used with the client id to transmit the data to the client.
+ *  The reason for using a client id is because the client
+ *  can be deleted in between receiving a command and sending a response.
+ *  E.g.
+ *  NetworkPerformanceClient (own thread, id 5)  <---  Dump Scene Command
+ *  delete NetworkPerformanceClient              <---  Connection closed
+ *  MainThread. Send scene data to client 5. Client 5 has been deleted so don't send the data.
+ *
+ */
+class NetworkPerformanceClient
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param thread thread pointer
+   * @param socket socket interface
+   * @param clientId unique client id
+   * @param triggerEventFactory used to create trigger events
+   * @param sendDataInterface used to send data to the socket from main thread
+   * @param SocketFactoryInterface used to delete the socket when the client is destroyed
+   */
+  NetworkPerformanceClient( pthread_t* thread,
+                            SocketInterface *socket,
+                            unsigned int clientId,
+                            TriggerEventFactoryInterface& triggerEventFactory,
+                            ClientSendDataInterface& sendDataInterface,
+                            SocketFactoryInterface& socketFactory );
+
+  /**
+   * @brief Destructor
+   */
+  ~NetworkPerformanceClient();
+
+  /**
+   * @return client unique id
+   */
+  unsigned int GetId() const;
+
+  /**
+   * @return socket interface
+   */
+  SocketInterface& GetSocket();
+
+  /**
+   * @brief Write data to a socket. Can be called from any thread
+   * @copydoc Dali::SocketInterface::Send
+   */
+  bool WriteSocket( const void* buffer, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Process a command
+   * @param buffer pointer to command data
+   * @param bufferSizeInBytes how big the buffer is in bytes
+   */
+  void ProcessCommand( char* buffer, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Write a marker to the socket, if this client is filtering this marker.
+   * @param marker
+   */
+  bool TransmitMarker( const PerformanceMarker& marker, const char* const description );
+
+  /**
+   * @brief If the client is waiting inside a select statement, this will cause it
+   * to break out.
+   */
+  void ExitSelect();
+
+  /**
+   * @brief get the thread running the client
+   * @return thread pointer
+   */
+  pthread_t* GetThread();
+
+private:
+
+  pthread_t* mThread;                                   ///< thread for the client
+  SocketInterface* mSocket;                             ///< socket interface
+  PerformanceMarker::MarkerFilter mMarkerBitmask;       ///< What markers are currently filtered
+  TriggerEventFactoryInterface& mTriggerEventFactory;   ///< Trigger event factory
+  ClientSendDataInterface& mSendDataInterface;          ///< used to send data to a client from the main event thread
+  SocketFactoryInterface& mSocketFactoryInterface;      ///< used to delete the socket
+  unsigned int mClientId;                               ///< unique client id
+  bool mConsoleClient;                                  ///< if connected via a console then all responses are in ASCII, not binary packed data.
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/performance-logging/networking/network-performance-protocol.cpp b/adaptors/base/performance-logging/networking/network-performance-protocol.cpp
new file mode 100644 (file)
index 0000000..91ccb7b
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+// CLASS HEADER
+#include "network-performance-protocol.h"
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace Dali
+{
+
+namespace PerformanceProtocol
+{
+
+namespace
+{
+
+/**
+ * Command parameter type
+ */
+enum PARAMETER_TYPE
+{
+  NO_PARAMS,
+  UNSIGNED_INT,
+  STRING
+};
+
+/**
+ * Command information structure
+ */
+struct CommandInfo
+{
+  CommandId     cmdId;
+  CommandString cmdString;
+  PARAMETER_TYPE paramType;
+};
+
+/**
+ * Command lookup table
+ */
+CommandInfo CommandLookup[]=
+{
+  {  HELP_MESSAGE               , "help"               ,NO_PARAMS     },
+  {  ENABLE_METRIC              , "enable_metric"      ,UNSIGNED_INT  },
+  {  DISABLE_METRIC             , "disable_metric"     ,UNSIGNED_INT  },
+  {  LIST_METRICS_AVAILABLE     , "list_metrics"       ,NO_PARAMS     },
+  {  ENABLE_TIME_MARKER_BIT_MASK, "set_marker",         UNSIGNED_INT  },
+  {  DUMP_SCENE_GRAPH           , "dump_scene"         ,NO_PARAMS     },
+  {  SET_PROPERTIES             , "set_properties"     ,STRING        },
+  {  UNKNOWN_COMMAND            , "unknown"            ,NO_PARAMS     }
+};
+const unsigned int CommandLookupLength = sizeof( CommandLookup ) /sizeof( CommandInfo );
+
+#define GREEN  "\033[01;32m"
+#define NORMAL  "\e[m"
+#define PARAM "\033[22;32m"
+#define YELLOW "\033[01;33m"
+
+const char* const helpMsg =
+    YELLOW
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+    "  Dali performance console                           \n"
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" NORMAL
+    GREEN " list_metrics " NORMAL " - list available metrics\n"
+    GREEN " enable_metric " PARAM " metricId" NORMAL " - enable a metric \n"
+    GREEN " disable_metric "PARAM " metricId" NORMAL " - disable a metric\n\n"
+    GREEN " set_marker " PARAM " value " NORMAL "-output Dali markers\n"
+    "            : Bit 0  = V_SYNC (1)\n"
+    "            : Bit 1  = Update task (2)\n"
+    "            : Bit 2  = Render task (4) \n"
+    "            : Bit 3  = Event Processing task (8)\n"
+    "            : Bit 4  = SwapBuffers (16)\n"
+    "            : Bit 5  = Life cycle events  (32)\n"
+    "            : Bit 6  = Resource event (64)\n"
+    "\n"
+    GREEN" set_properties "NORMAL " - set an actor property command. Format:\n\n"
+    GREEN" set_properties "PARAM"|ActorIndex;Property;Value|" NORMAL ", e.g: \n"
+    GREEN" set_properties " PARAM "|178;Size;[ 144.0, 144.0, 144.0 ]|178;Color;[ 1.0, 1,0, 1.0 ]|\n"
+    "\n"
+    GREEN " dump_scene" NORMAL " - dump the current scene in json format\n";
+
+} // un-named namespace
+
+bool GetCommandId( const char* const commandString, unsigned int lengthInBytes, CommandId& commandId, unsigned int& intParam, std::string& stringParam  )
+{
+  commandId = UNKNOWN_COMMAND;
+  intParam = 0;
+
+  // the command list is small so just do a O(n) search for the commandID.
+  for( unsigned int i = 0 ; i < CommandLookupLength; ++i )
+  {
+    if( strncmp( commandString, CommandLookup[i].cmdString ,strlen(CommandLookup[i].cmdString  )) == 0 )
+    {
+      commandId = CommandLookup[i].cmdId;
+
+      // if the command has a parameter read it
+      if( CommandLookup[i].paramType ==  UNSIGNED_INT)
+      {
+        int count = sscanf(commandString,"%*s %d",&intParam);
+        if( count != 1 )
+        {
+          // missing parameter
+          return false;
+        }
+      }
+      else if (CommandLookup[i].paramType == STRING )
+      {
+        char* charParam( NULL );
+        // allocates the character array
+        int count = sscanf(commandString,"%*s %ms",&charParam);
+        if( count != 1 )
+        {
+          // missing parameter
+          return false;
+        }
+        stringParam = std::string( charParam);
+        free(charParam);
+      }
+      return true;
+    }
+  }
+  // not found
+  return false;
+}
+
+bool GetCommandString( CommandId commandId, CommandString& commandString )
+{
+  for( unsigned int i = 0; i < CommandLookupLength; ++i)
+  {
+    if( CommandLookup[ i ].cmdId == commandId )
+    {
+      strncpy( commandString,  CommandLookup[ i ].cmdString, strlen(CommandLookup[ i ].cmdString) );
+      return true;
+    }
+  }
+  strncpy( commandString, CommandLookup[ UNKNOWN_COMMAND ].cmdString, MAX_COMMAND_STRING_LENGTH);
+  return false;
+}
+
+const char* const GetHelpMessage()
+{
+  return helpMsg;
+}
+
+
+} // namespace PerformanceProtocol
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/networking/network-performance-protocol.h b/adaptors/base/performance-logging/networking/network-performance-protocol.h
new file mode 100644 (file)
index 0000000..e3dfcb1
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H__
+#define __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+
+namespace PerformanceProtocol
+{
+
+const unsigned int MAX_COMMAND_STRING_LENGTH = 256;  ///< maximum length of a command including null terminator
+
+/**
+ * @brief List of commands id's
+ */
+enum CommandId
+{
+  HELP_MESSAGE            = 0, ///<  help message
+  ENABLE_METRIC           = 1, ///< enable metric
+  DISABLE_METRIC          = 2, ///< disable metric
+  LIST_METRICS_AVAILABLE  = 3, ///< list  metrics that are available
+  ENABLE_TIME_MARKER_BIT_MASK = 4, ///< bit mask of time markers to enable
+  SET_PROPERTIES            = 5, ///< set property
+  DUMP_SCENE_GRAPH          = 6, ///< dump the scene graph
+  UNKNOWN_COMMAND           = 4096
+};
+
+
+typedef char CommandString[ MAX_COMMAND_STRING_LENGTH ];
+
+/**
+ * @brief given a command id, get the command string
+ * @param[in] commandId command id
+ * @param[out] commandString command string
+ * @return true on success, false on failure
+ */
+bool GetCommandString( CommandId commandId, CommandString& commandString );
+
+/**
+ * @brief given a command string, get the command id and an integer parameter if it exists
+ * @param[in] commandString command string
+ * @param[in] lengthInBytes length of the string
+ * @param[out] commandId command id
+ * @param[out] intParam integer parameter
+ * @param[out] stringParam string parameter
+ * @param true on success, false on failure
+ */
+bool GetCommandId( const char* const commandString,
+                   unsigned int lengthInBytes,
+                   CommandId& commandId,
+                   unsigned int& intParam,
+                   std::string& stringParam);
+
+/**
+ * @return the protocol help message for console users
+ */
+const char* const GetHelpMessage();
+
+} // namespace PerformanceProtocol
+
+} // namespace Dali
+
+#endif //__DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H__
diff --git a/adaptors/base/performance-logging/networking/network-performance-server.cpp b/adaptors/base/performance-logging/networking/network-performance-server.cpp
new file mode 100644 (file)
index 0000000..4d86afb
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "network-performance-server.h"
+
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/performance-marker.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // un-named namespace
+{
+const unsigned int SERVER_PORT = 3031;
+const unsigned int MAXIMUM_PORTS_TO_TRY = 10; ///< if port in use, try up to SERVER_PORT + 10
+const unsigned int CONNECTION_BACKLOG = 2;   ///<  maximum length of the queue of pending connections.
+const unsigned int SOCKET_READ_BUFFER_SIZE = 4096;
+typedef Vector< NetworkPerformanceClient*> ClientList;
+
+/**
+ * POD passed to client thread on startup
+ */
+struct ClientThreadInfo
+{
+  NetworkPerformanceServer* server;
+  NetworkPerformanceClient* client;
+};
+}
+
+NetworkPerformanceServer::NetworkPerformanceServer( AdaptorInternalServices& adaptorServices,
+                                                    const EnvironmentOptions& logOptions )
+: mTriggerEventFactory( adaptorServices.GetTriggerEventFactoryInterface() ),
+  mSocketFactory( adaptorServices.GetSocketFactoryInterface() ),
+  mLogOptions( logOptions ),
+  mServerThread( 0 ),
+  mListeningSocket( NULL ),
+  mClientUniqueId( 0 ),
+  mClientCount( 0 ),
+  mLogFunctionInstalled( false )
+{
+}
+
+NetworkPerformanceServer::~NetworkPerformanceServer()
+{
+  Stop();
+
+  if( mLogFunctionInstalled )
+  {
+    mLogOptions.UnInstallLogFunction();
+  }
+}
+
+void NetworkPerformanceServer::Start()
+{
+  // start a thread to listen for incoming connection requests
+  if (! mServerThread )
+  {
+    if( mListeningSocket )
+    {
+      mSocketFactory.DestroySocket( mListeningSocket );
+    }
+    mListeningSocket = mSocketFactory.NewSocket( SocketInterface::TCP);
+    mListeningSocket->ReuseAddress( true );
+
+    bool bound = false;
+    unsigned int basePort = 0;
+
+    // try a small range of ports, so if multiple Dali apps are running you can select
+    // which one to connect to
+    while( !bound && ( basePort <  MAXIMUM_PORTS_TO_TRY ))
+    {
+      bound = mListeningSocket->Bind( SERVER_PORT + basePort );
+      if( !bound )
+      {
+        basePort++;
+      }
+    }
+    if(!bound )
+    {
+      DALI_LOG_ERROR("Failed to bind to a port \n");
+      return;
+    }
+
+    mListeningSocket->Listen( CONNECTION_BACKLOG );
+
+    // start a thread which will block waiting for new connections
+    int error = pthread_create( &mServerThread, NULL, ConnectionListenerFunc, this );
+    DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+    Dali::Integration::Log::LogMessage(Integration::Log::DebugInfo, "~~~ NetworkPerformanceServer started on port %d ~~~ \n",  SERVER_PORT + basePort);
+
+  }
+}
+void NetworkPerformanceServer::Stop()
+{
+  if( !mServerThread )
+  {
+    return;
+  }
+  // close the server thread to prevent any new connections
+  mListeningSocket->ExitSelect();
+
+  // wait for the thread to exit.
+  void* exitValue;
+  pthread_join( mServerThread, &exitValue );
+
+  // close the socket
+  mListeningSocket->CloseSocket();
+
+  mSocketFactory.DestroySocket( mListeningSocket );
+
+  mListeningSocket = NULL;
+
+  // this will tell all client threads to quit
+  StopClients();
+
+}
+
+bool NetworkPerformanceServer::IsRunning() const
+{
+  if (mServerThread )
+  {
+    return true;
+  }
+  return false;
+}
+
+void NetworkPerformanceServer::ClientThread( NetworkPerformanceClient* client )
+{
+  mClientCount++;
+
+  SocketInterface& socket( client->GetSocket() );
+
+  for( ;; )
+  {
+    SocketInterface::SelectReturn ret = socket.Select();
+
+    if( ret == SocketInterface::DATA_AVAILABLE )
+    {
+     // Read
+      char buffer[ SOCKET_READ_BUFFER_SIZE ];
+      unsigned int  bytesRead;
+
+      bool ok  = socket.Read( buffer, sizeof( buffer ) , bytesRead);
+      if( ok && ( bytesRead > 0) )
+      {
+        client->ProcessCommand( buffer, bytesRead );
+      }
+      else   // if bytesRead == 0, then client closed connection, if ok == false then an error
+      {
+        DeleteClient( client );
+        return;
+      }
+    }
+    else // ret == QUIT or ERROR
+    {
+      DeleteClient( client);
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::ConnectionListener()
+{
+  // install Dali logging function for this thread
+  if( !mLogFunctionInstalled )
+  {
+    mLogOptions.InstallLogFunction();
+    mLogFunctionInstalled = true;
+  }
+
+  for( ;; )
+  {
+    // this will block, waiting for a client to connect
+    // or for mListeningSocket->ExitSelect() to be called
+
+    SocketInterface::SelectReturn ret = mListeningSocket->Select();
+
+    if( ret == SocketInterface::DATA_AVAILABLE )
+    {
+      SocketInterface* clientSocket = mListeningSocket->Accept();
+
+      // new connection made, spawn a thread to handle it
+      pthread_t* clientThread = new pthread_t();
+
+      NetworkPerformanceClient* client = AddClient( clientSocket, clientThread );
+
+      ClientThreadInfo* info = new ClientThreadInfo;
+      info->client = client;
+      info->server = this;
+
+      int error = pthread_create( clientThread, NULL, ClientThreadFunc, info );
+      DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+    }
+    else // ret == SocketInterface::QUIT or SocketInterface::ERROR
+    {
+      return;
+    }
+  }
+}
+
+void* NetworkPerformanceServer::ClientThreadFunc( void* data )
+{
+  ClientThreadInfo* info = static_cast<ClientThreadInfo*>( data );
+  info->server->ClientThread( info->client );
+  delete info;
+  return NULL;
+}
+
+NetworkPerformanceClient* NetworkPerformanceServer::AddClient( SocketInterface* clientSocket, pthread_t* clientThread )
+{
+  // This function is only called from the listening thread
+  NetworkPerformanceClient* client= new NetworkPerformanceClient( clientThread,
+                                                                  clientSocket,
+                                                                  mClientUniqueId++,
+                                                                  mTriggerEventFactory,
+                                                                  *this,
+                                                                  mSocketFactory);
+
+  // protect the mClients list which can be accessed from multiple threads.
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  mClients.PushBack( client );
+
+  return client;
+}
+
+void NetworkPerformanceServer::DeleteClient( NetworkPerformanceClient* client )
+{
+  // protect the mClients list while modifying
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  // remove from the list, and delete it
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    if( (*iter) == client )
+    {
+      mClients.Erase( iter );
+      delete client;
+
+      // if there server is shutting down, it waits for client count to hit zero
+      mClientCount--;
+
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::SendData( const char* const data, unsigned int bufferSizeInBytes,unsigned int clientId )
+{
+  if( ! mClientCount )
+  {
+    return;
+  }
+
+  // prevent clients been added / deleted while transmiting data
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    if( client->GetId() == clientId )
+    {
+      client->WriteSocket(data ,bufferSizeInBytes);
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+  if( ! IsRunning() )
+  {
+    return;
+  }
+  // prevent clients been added / deleted while transmiting data
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    client->TransmitMarker( marker, description );
+  }
+}
+
+
+void NetworkPerformanceServer::StopClients()
+{
+  // prevent clients been added / deleted while stopping all clients
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    // stop the client from waiting for new commands, and exit from it's thread
+    client->ExitSelect();
+
+    void* exitValue;
+    pthread_t* thread = client->GetThread();
+    pthread_join( *thread, &exitValue );
+    delete thread;
+
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/networking/network-performance-server.h b/adaptors/base/performance-logging/networking/network-performance-server.h
new file mode 100644 (file)
index 0000000..6cff347
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H__
+#define __DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+#include <dali/devel-api/common/mutex.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <base/environment-options.h>
+#include <base/performance-logging/networking/network-performance-client.h>
+#include <base/interfaces/adaptor-internal-services.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class SocketInterface;
+class PerformanceMarker;
+
+/**
+ *  @brief  The class listens for incoming connections on a dedicated thread.
+ *
+ *  When a new connection is established a client thread is spawned to
+ *  handle that connection, along with a NetworkPerformanceClient object.
+ *  The NetworkPerformanceClient object performs processing of incoming
+ *  commands and holds the per-client state information for performance monitoring.
+ *
+ *  Server->Start()
+ *  - Open socket
+ *  - Spawns a thread to listen for incoming connections
+ *  <---- New connection
+ *  - Spawns a client thread to communicate with new client
+ *
+ *  Server->Stop()
+ *  - Stops listening thread
+ *  - Stops all client threads
+ */
+class NetworkPerformanceServer : public ClientSendDataInterface
+{
+
+public:
+
+  /**
+   * @brief Constructor
+   * @param[in] adaptorServices adaptor internal services
+   * @param[in] logOptions log options
+   */
+  NetworkPerformanceServer( AdaptorInternalServices& adaptorServices, const EnvironmentOptions& logOptions );
+
+
+  /**
+   * @brief Start the server, to be called form Dali main thread
+   * @pre Can only be called form Dali main thread
+   */
+  void Start();
+
+  /**
+   * @brief Stop the server
+   * @pre Can only be called form Dali main thread
+   */
+  void Stop();
+
+  /**
+   * @return true if the server is running
+   */
+  bool IsRunning() const;
+
+  /**
+   * @brief Transmit a marker to any clients are listening for this marker.
+   * @param[in] marker performance marker
+   * @param[in] description marker description
+   * @pre Can be called from any thread
+   *
+   */
+  void TransmitMarker( const PerformanceMarker& marker, const char* const description );
+
+  /**
+   * Destructor
+   */
+   ~NetworkPerformanceServer();
+
+protected:  // ClientSendDataInterface
+
+  /**
+   * @copydoc ClientSendDataInterface::ClientSendDataInterface()
+   */
+  virtual void SendData( const char* const data, unsigned int bufferSizeInBytes, unsigned int clientId );
+
+private:
+
+  /**
+   * Helper for the thread calling the entry function.
+   * @param[in] This A pointer to the current RenderThread object
+   */
+  static void* ConnectionListenerFunc( void* This )
+  {
+    ( static_cast<NetworkPerformanceServer*>( This ) )->ConnectionListener();
+    return NULL;
+  }
+
+  /**
+   * Helper for the thread calling the entry function.
+   * @param[in] This A pointer to the current RenderThread object
+   */
+  static void* ClientThreadFunc( void* data );
+
+  /**
+   * @brief Client thread function
+   * @param client network client object
+   */
+  void ClientThread( NetworkPerformanceClient* client );
+
+  /**
+   * @brief Stop all client threads
+   */
+  void StopClients();
+
+  /**
+   * @brief Waits for new connections to be made
+   */
+  void ConnectionListener();
+
+  /**
+   * @brief Add a new client to the client list
+   * @param clientSocket client socket
+   * @param clientThread client thread
+   * @return client
+   */
+  NetworkPerformanceClient* AddClient( SocketInterface* clientSocket, pthread_t* clientThread );
+
+  /**
+   * @brief Delete a client from the client list
+   * @param client  network client
+   */
+  void DeleteClient( NetworkPerformanceClient* client );
+
+  NetworkPerformanceServer( const NetworkPerformanceServer& );            ///< undefined copy constructor
+  NetworkPerformanceServer& operator=( const NetworkPerformanceServer& ); ///< undefined assignment operator
+
+
+  TriggerEventFactoryInterface& mTriggerEventFactory;     ///< used to create trigger events
+  SocketFactoryInterface& mSocketFactory;                 ///< used to create sockets
+  const EnvironmentOptions& mLogOptions;                  ///< log options
+  Dali::Vector< NetworkPerformanceClient* > mClients;     ///< list of connected clients
+  pthread_t mServerThread;                                ///< thread that listens for new connections
+  SocketInterface* mListeningSocket;                      ///< socket used to listen for new connections
+  Dali::Mutex mClientListMutex;                           ///< mutex
+  unsigned int mClientUniqueId;                           ///< increments for every client connection
+  volatile unsigned int mClientCount;                     ///< client count
+  bool mLogFunctionInstalled;                             ///< whether the log function is installed
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif //__DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H__
diff --git a/adaptors/base/performance-logging/performance-interface-factory.cpp b/adaptors/base/performance-logging/performance-interface-factory.cpp
new file mode 100644 (file)
index 0000000..ebd4f8a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "performance-interface-factory.h"
+
+// INTERNAL INCLUDES
+#include "performance-server.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+PerformanceInterface* PerformanceInterfaceFactory::CreateInterface(
+                                 AdaptorInternalServices& adaptorServices,
+                                 const EnvironmentOptions& environmentOptions  )
+{
+  return new PerformanceServer( adaptorServices, environmentOptions );
+}
+
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/performance-interface-factory.h b/adaptors/base/performance-logging/performance-interface-factory.h
new file mode 100644 (file)
index 0000000..abbe0d1
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef __DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H__
+#define __DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Performance interface factory class
+ *
+ */
+class PerformanceInterfaceFactory
+{
+public:
+
+  /**
+   * Create a new concrete implementation of the performance interface.
+   * @param adaptorServices adaptor internal services
+   * @param environmentOptions environment options
+   * @return pointer to a new performance interface
+   */
+  static PerformanceInterface* CreateInterface( AdaptorInternalServices& adaptorServices,
+                                                const EnvironmentOptions& environmentOptions );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H__
diff --git a/adaptors/base/performance-logging/performance-marker.cpp b/adaptors/base/performance-logging/performance-marker.cpp
new file mode 100644 (file)
index 0000000..05b3258
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "performance-marker.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+struct NamePair
+{
+  PerformanceInterface::MarkerType type;
+  const char* const name;
+  PerformanceMarker::MarkerFilter group;
+  PerformanceMarker::MarkerEventType eventType;
+};
+
+const NamePair MARKER_LOOKUP[] =
+{
+    // timed event names must be postfixed with with _START and _END
+    // this is to allow tracers to extract the event name by removing the _START, _END strings
+    //
+    { PerformanceInterface::VSYNC       ,         "V_SYNC"               , PerformanceMarker::V_SYNC_EVENTS, PerformanceMarker::SINGLE_EVENT      },
+    { PerformanceInterface::UPDATE_START ,        "UPDATE_START"         , PerformanceMarker::UPDATE,        PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::UPDATE_END   ,        "UPDATE_END"           , PerformanceMarker::UPDATE,        PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::RENDER_START ,        "RENDER_START"         , PerformanceMarker::RENDER,        PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::RENDER_END   ,        "RENDER_END"           , PerformanceMarker::RENDER,        PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::SWAP_START   ,        "SWAP_START"           , PerformanceMarker::SWAP_BUFFERS,  PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::SWAP_END     ,        "SWAP_END"             , PerformanceMarker::SWAP_BUFFERS,  PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::PROCESS_EVENTS_START, "PROCESS_EVENT_START"  , PerformanceMarker::EVENT_PROCESS, PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::PROCESS_EVENTS_END,   "PROCESS_EVENT_END"    , PerformanceMarker::EVENT_PROCESS, PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::PAUSED       ,        "PAUSED"               , PerformanceMarker::LIFE_CYCLE_EVENTS, PerformanceMarker::SINGLE_EVENT  },
+    { PerformanceInterface::RESUME       ,        "RESUMED"              , PerformanceMarker::LIFE_CYCLE_EVENTS, PerformanceMarker::SINGLE_EVENT  },
+    { PerformanceInterface::START        ,        "START"                , PerformanceMarker::CUSTOM_EVENTS, PerformanceMarker::START_TIMED_EVENT  },
+    { PerformanceInterface::END          ,        "END"                  , PerformanceMarker::CUSTOM_EVENTS, PerformanceMarker::END_TIMED_EVENT  }
+};
+} // un-named namespace
+
+
+
+PerformanceMarker::PerformanceMarker( PerformanceInterface::MarkerType type )
+:mType(type)
+{
+}
+
+PerformanceMarker::PerformanceMarker( PerformanceInterface::MarkerType type, FrameTimeStamp frameInfo )
+:mType(type),
+ mTimeStamp(frameInfo)
+{
+}
+
+const char* const PerformanceMarker::GetName( ) const
+{
+  return MARKER_LOOKUP[ mType ].name;
+}
+
+PerformanceMarker::MarkerEventType PerformanceMarker::GetEventType() const
+{
+  return MARKER_LOOKUP[ mType ].eventType;
+}
+
+PerformanceMarker::MarkerFilter PerformanceMarker::GetFilterType() const
+{
+  return MARKER_LOOKUP[ mType ].group;
+}
+
+unsigned int PerformanceMarker::MicrosecondDiff( const PerformanceMarker& start,const PerformanceMarker& end )
+{
+  return FrameTimeStamp::MicrosecondDiff( start.mTimeStamp, end.mTimeStamp );
+}
+
+bool PerformanceMarker::IsFilterEnabled( MarkerFilter filter ) const
+{
+  return  (filter & MARKER_LOOKUP[ mType ].group);
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/adaptors/base/performance-logging/performance-marker.h b/adaptors/base/performance-logging/performance-marker.h
new file mode 100644 (file)
index 0000000..9651770
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H__
+#define __DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <base/interfaces/performance-interface.h>
+#include <base/performance-logging/frame-time-stamp.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Marker used to record an event with a time stamp in Dali
+ */
+class PerformanceMarker
+{
+public:
+
+
+  /**
+   * Bitmask used to filter different types of markers based
+   * on what group they belong to.
+   */
+  enum MarkerFilter
+  {
+    FILTERING_DISABLED   = 0,      ///< disabled
+    V_SYNC_EVENTS        = 1 << 0, ///< v-sync
+    UPDATE               = 1 << 1, ///< update start / end
+    RENDER               = 1 << 2, ///< render start / end
+    EVENT_PROCESS        = 1 << 3, ///< process events start / end
+    SWAP_BUFFERS         = 1 << 4, ///< swap buffers start / end
+    LIFE_CYCLE_EVENTS    = 1 << 5, ///< pause / resume
+    RESOURCE_EVENTS      = 1 << 6, ///< resource events
+    CUSTOM_EVENTS        = 1 << 7
+  };
+
+  /**
+   * Marker event type
+   */
+  enum MarkerEventType
+  {
+    SINGLE_EVENT,           ///< event is something that has no duration associated with it
+    START_TIMED_EVENT,      ///< start of a timed event
+    END_TIMED_EVENT         ///< end of a timed event
+
+  };
+
+
+  /**
+   * @brief Constructor
+   * @param[in] type marker type
+   */
+  PerformanceMarker( PerformanceInterface::MarkerType type );
+
+  /**
+   * @brief Constructor
+   * @param[in] type marker type
+   * @param[in] time time stamp
+   */
+  PerformanceMarker( PerformanceInterface::MarkerType type,  FrameTimeStamp time );
+
+  /**
+   * @return the time stamp
+   */
+  const FrameTimeStamp& GetTimeStamp() const
+  {
+    return mTimeStamp;
+  }
+
+  /**
+   * @return the type of marker
+   */
+  PerformanceInterface::MarkerType GetType() const
+  {
+    return mType;
+  }
+
+  /**
+   * @return the event type of marker
+   */
+  MarkerEventType GetEventType() const;
+
+  /**
+   * @return the filter type of marker
+   */
+  MarkerFilter GetFilterType() const;
+
+
+  /**
+   * @return marker name
+   */
+  const char* const GetName( ) const;
+
+  /**
+   * @param start the start marker
+   * @param end the end marker
+   * @return difference in microseconds between two markers
+   */
+  static unsigned int MicrosecondDiff( const PerformanceMarker& start, const PerformanceMarker& end  );
+
+  /**
+   * @return if a marker is enabled as part of a group
+   */
+  bool IsFilterEnabled( MarkerFilter filter ) const;
+private:
+
+  PerformanceInterface::MarkerType mType;         ///< marker type
+  FrameTimeStamp mTimeStamp;                      ///< frame time stamp
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H__
diff --git a/adaptors/base/performance-logging/performance-server.cpp b/adaptors/base/performance-logging/performance-server.cpp
new file mode 100644 (file)
index 0000000..5b6773f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "performance-server.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+PerformanceServer::PerformanceServer( AdaptorInternalServices& adaptorServices,
+                                      const EnvironmentOptions& environmentOptions)
+:mPlatformAbstraction( adaptorServices.GetPlatformAbstractionInterface() ),
+ mEnvironmentOptions( environmentOptions ),
+ mKernelTrace( adaptorServices.GetKernelTraceInterface() ),
+ mSystemTrace( adaptorServices.GetSystemTraceInterface() ),
+ mNetworkServer( adaptorServices, environmentOptions ),
+ mStatContextManager( *this ),
+ mStatisticsLogBitmask( 0 ),
+ mNetworkControlEnabled( mEnvironmentOptions.GetNetworkControlMode()),
+ mLoggingEnabled( false ),
+ mLogFunctionInstalled( false )
+{
+  SetLogging( mEnvironmentOptions.GetPerformanceStatsLoggingOptions(),
+              mEnvironmentOptions.GetPerformanceTimeStampOutput(),
+              mEnvironmentOptions.GetPerformanceStatsLoggingFrequency());
+
+  if( mNetworkControlEnabled )
+  {
+    mLoggingEnabled  = true;
+    mNetworkServer.Start();
+  }
+}
+
+PerformanceServer::~PerformanceServer()
+{
+  if( mNetworkControlEnabled )
+  {
+    mNetworkServer.Stop();
+  }
+
+  if( mLogFunctionInstalled )
+  {
+    mEnvironmentOptions.UnInstallLogFunction();
+  }
+}
+
+void PerformanceServer::SetLogging( unsigned int statisticsLogOptions,
+                                    unsigned int timeStampOutput,
+                                    unsigned int logFrequency )
+{
+  mStatisticsLogBitmask = statisticsLogOptions;
+  mPerformanceOutputBitmask = timeStampOutput;
+
+  mStatContextManager.SetLoggingLevel( mStatisticsLogBitmask, logFrequency);
+
+  if( ( mStatisticsLogBitmask == 0) && ( mPerformanceOutputBitmask == 0 ))
+  {
+    mLoggingEnabled = false;
+  }
+  else
+  {
+    mLoggingEnabled = true;
+  }
+}
+
+void PerformanceServer::SetLoggingFrequency( unsigned int logFrequency, ContextId contextId )
+{
+  mStatContextManager.SetLoggingFrequency( logFrequency, contextId );
+}
+
+void PerformanceServer::EnableLogging( bool enable, ContextId contextId )
+{
+  mStatContextManager.EnableLogging( enable, contextId );
+}
+
+PerformanceInterface::ContextId PerformanceServer::AddContext( const char* name )
+{
+  // for adding custom contexts
+  return mStatContextManager.AddContext( name, PerformanceMarker::CUSTOM_EVENTS );
+}
+
+void PerformanceServer::RemoveContext( ContextId contextId )
+{
+  mStatContextManager.RemoveContext( contextId );
+}
+
+void PerformanceServer::AddMarker( MarkerType markerType, ContextId contextId )
+{
+  // called only for custom markers
+
+  if( !mLoggingEnabled )
+  {
+    return;
+  }
+
+  // Get the time stamp
+  unsigned int seconds = 0;
+  unsigned int microseconds = 0;
+  mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds );
+
+  // Create a marker
+  PerformanceMarker marker( markerType, FrameTimeStamp( 0, seconds, microseconds ) );
+
+  // get the marker description for this context, e.g SIZE_NEGOTIATION_START
+  const char* const description = mStatContextManager.GetMarkerDescription( markerType, contextId );
+
+  // log it
+  LogMarker( marker, description );
+
+  // Add custom marker to statistics context manager
+  mStatContextManager.AddCustomMarker( marker, contextId );
+}
+
+void PerformanceServer::AddMarker( MarkerType markerType )
+{
+  // called only for internal markers
+
+  if( !mLoggingEnabled )
+  {
+    return;
+  }
+
+  if( markerType == VSYNC )
+  {
+    // make sure log function is installed, note this will be called only from v-sync thread
+    // if the v-sync thread has already installed one, it won't make any difference.
+    if( ! mLogFunctionInstalled )
+    {
+      mEnvironmentOptions.InstallLogFunction();
+      mLogFunctionInstalled = true;
+    }
+  }
+
+  // Get the time
+  unsigned int seconds = 0;
+  unsigned int microseconds = 0;
+  mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds );
+
+  // Create a marker
+  PerformanceMarker marker( markerType, FrameTimeStamp( 0, seconds, microseconds ) );
+
+  // log it
+  LogMarker(marker, marker.GetName() );
+
+  // Add internal marker to statistics context manager
+  mStatContextManager.AddInternalMarker( marker );
+
+}
+
+void PerformanceServer::LogContextStatistics( const char* const text )
+{
+  Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, text );
+}
+
+void PerformanceServer::LogMarker( const PerformanceMarker& marker, const char* const description )
+{
+  // log to the network ( this is thread safe )
+  if( mNetworkControlEnabled )
+  {
+    mNetworkServer.TransmitMarker( marker, description );
+  }
+
+  // log to kernel trace
+  if( mPerformanceOutputBitmask & OUTPUT_KERNEL_TRACE )
+  {
+    // Kernel tracing implementation may not be thread safe
+    Mutex::ScopedLock lock( mLogMutex );
+    // description will be something like UPDATE_START or UPDATE_END
+    mKernelTrace.Trace( marker, description );
+  }
+
+  // log to system trace
+  if( mPerformanceOutputBitmask & OUTPUT_SYSTEM_TRACE )
+  {
+    // System  tracing implementation may not be thread safe
+    Mutex::ScopedLock lock( mLogMutex );
+
+    mSystemTrace.Trace( marker, description );
+  }
+
+  // log to Dali log ( this is thread safe )
+  if ( mPerformanceOutputBitmask & OUTPUT_DALI_LOG )
+  {
+    Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo,
+                                    "%d.%06d (seconds), %s\n",
+                                    marker.GetTimeStamp().seconds,
+                                    marker.GetTimeStamp().microseconds,
+                                    description);
+  }
+}
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/performance-server.h b/adaptors/base/performance-logging/performance-server.h
new file mode 100644 (file)
index 0000000..8c71900
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H__
+#define __DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLDUES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/devel-api/common/mutex.h>
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/frame-time-stats.h>
+#include <base/performance-logging/networking/network-performance-server.h>
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/performance-logging/performance-marker.h>
+#include <base/performance-logging/statistics/stat-context-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EnvironmentOptions;
+class StatContext;
+/**
+ * Concrete implementation of performance interface.
+ * Adaptor classes should never include this file, they
+ * just need to include the abstract class performance-interface.h
+ */
+class PerformanceServer : public PerformanceInterface, public StatContextLogInterface
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param[in] adaptorServices adaptor internal services
+   * @param[in] environmentOptions environment options
+   */
+  PerformanceServer( AdaptorInternalServices& adaptorServices,
+                     const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Destructor
+   */
+  virtual ~PerformanceServer();
+
+  /**
+   * @copydoc PerformanceLogger::AddContext()
+   */
+  virtual ContextId AddContext( const char* name );
+
+  /**
+   * @copydoc PerformanceLogger::RemoveContext()
+   */
+  virtual void RemoveContext( ContextId contextId );
+
+  /**
+   * @copydoc PerformanceInterface::AddMarker( MarkerType markerType )
+   */
+  virtual void AddMarker( MarkerType markerType );
+
+  /**
+   * @copydoc PerformanceLogger::AddMarker( MarkerType markerType, ContextId contextId )
+   */
+  virtual void AddMarker( MarkerType markerType, ContextId contextId );
+
+  /**
+   * @copydoc PerformanceInterface::SetLogging()
+   */
+  virtual void SetLogging( unsigned int statisticsLogOptions,
+                           unsigned int timeStampOutput,
+                           unsigned int logFrequency );
+
+  /**
+   * @copydoc PerformanceLogger::SetLoggingFrequency()
+   */
+  virtual void SetLoggingFrequency( unsigned int logFrequency, ContextId contextId );
+
+  /**
+   * @copydoc PerformanceLogger::EnableLogging()
+   */
+  virtual void EnableLogging( bool enable, ContextId contextId );
+
+public: //StatLogInterface
+
+  /**
+   * @copydoc StatLogInterface::LogContextStatistics()
+   */
+  virtual void LogContextStatistics( const char* const text );
+
+private:
+
+  /**
+   * @brief log the marker out to kernel/ DALi log
+   * @param[in] marker performance marker
+   * @param[in] description marker description
+   */
+  void LogMarker( const PerformanceMarker& marker, const char* const description );
+
+private:
+
+  Integration::PlatformAbstraction& mPlatformAbstraction; ///< platform abstraction
+  const EnvironmentOptions& mEnvironmentOptions;          ///< environment options
+  TraceInterface& mKernelTrace;                           ///< kernel trace interface
+  TraceInterface& mSystemTrace;                           ///< system trace interface
+  Dali::Mutex mLogMutex;                                  ///< mutex
+  NetworkPerformanceServer mNetworkServer;                ///< network server
+  StatContextManager mStatContextManager;                 ///< Stat context manager
+  unsigned int mStatisticsLogBitmask;                     ///< statistics log level
+  unsigned int mPerformanceOutputBitmask;                 ///< performance marker output
+  bool mNetworkControlEnabled:1;                          ///< Whether network control is enabled
+  bool mLoggingEnabled:1;                                 ///< whether logging update / render to a log is enabled
+  bool mLogFunctionInstalled:1;                           ///< whether the log function is installed
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/performance-logging/statistics/stat-context-log-interface.h b/adaptors/base/performance-logging/statistics/stat-context-log-interface.h
new file mode 100644 (file)
index 0000000..c8e9409
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H__
+#define __DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief  Abstract interface used to log statistics data
+ */
+class StatContextLogInterface
+{
+public:
+
+  /**
+   * @brief Used to log statistics out
+   * @param[in] text log the text
+   */
+  virtual void LogContextStatistics( const char* const text) = 0;
+
+
+protected:
+
+  /**
+   * @brief  Constructor
+   */
+  StatContextLogInterface()
+  {
+  }
+
+  /**
+   * @brief Virtual Destructor
+   */
+  virtual ~StatContextLogInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  StatContextLogInterface( const StatContextLogInterface& );
+
+  // Undefined assignment operator.
+  StatContextLogInterface& operator=( const StatContextLogInterface& );
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H__
diff --git a/adaptors/base/performance-logging/statistics/stat-context-manager.cpp b/adaptors/base/performance-logging/statistics/stat-context-manager.cpp
new file mode 100644 (file)
index 0000000..bdc86ec
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "stat-context-manager.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* const UPDATE_CONTEXT_NAME = "Update";
+const char* const RENDER_CONTEXT_NAME = "Render";
+const char* const EVENT_CONTEXT_NAME = "Event";
+const unsigned int DEFAULT_LOG_FREQUENCY = 2;
+}
+
+StatContextManager::StatContextManager( StatContextLogInterface& logInterface )
+: mLogInterface( logInterface ),
+  mNextContextId( 0 ),
+  mStatisticsLogBitmask(0),
+  mLogFrequency( DEFAULT_LOG_FREQUENCY )
+{
+
+  mStatContexts.Reserve(4); // intially reserve enough for 3 internal + 1 custom
+
+  // Add defaults
+  mUpdateStats = AddContext( UPDATE_CONTEXT_NAME, PerformanceMarker::UPDATE );
+  mRenderStats = AddContext( RENDER_CONTEXT_NAME, PerformanceMarker::RENDER );
+  mEventStats = AddContext( EVENT_CONTEXT_NAME,   PerformanceMarker::EVENT_PROCESS );
+
+}
+
+StatContextManager::~StatContextManager()
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+    delete context;
+  }
+  mStatContexts.Clear();
+}
+PerformanceInterface::ContextId StatContextManager::AddContext( const char* const name,
+                                                                PerformanceMarker::MarkerFilter type  )
+{
+  unsigned int contextId = mNextContextId++;
+
+  DALI_ASSERT_DEBUG( NULL == GetContext( contextId ) );
+
+  // logging enabled by default
+  StatContext* statContext = new StatContext( contextId, name, type,  mLogFrequency , mLogInterface );
+
+  // check to see if custom markers are enabled
+  if( ! ( mStatisticsLogBitmask & PerformanceInterface::LOG_CUSTOM_MARKERS ) )
+  {
+    statContext->EnableLogging( false );
+  }
+
+  mStatContexts.PushBack( statContext );
+
+  return contextId;
+}
+
+void StatContextManager::AddInternalMarker( const PerformanceMarker& marker )
+{
+  // log to the stat contexts, can be called from multiple threads so we
+  // protect the data
+  Mutex::ScopedLock lock( mDataMutex );
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+    context->ProcessInternalMarker( marker );
+  }
+}
+
+void StatContextManager::AddCustomMarker( const PerformanceMarker& marker, PerformanceInterface::ContextId contextId )
+{
+  // log to the stat contexts, can be called from multiple threads so we
+  // protect the data
+  Mutex::ScopedLock lock( mDataMutex );
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    context->ProcessCustomMarker( marker );
+  }
+}
+
+void StatContextManager::RemoveContext(PerformanceInterface::ContextId contextId )
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+
+    if( context->GetId() == contextId )
+    {
+      delete context;
+      mStatContexts.Erase( it );
+      return;
+    }
+  }
+}
+
+
+void StatContextManager::EnableLogging( bool enable, PerformanceInterface::ContextId contextId )
+{
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    context->EnableLogging( enable );
+  }
+}
+
+void StatContextManager::SetLoggingLevel(  unsigned int statisticsLogOptions, unsigned int logFrequency)
+{
+  mStatisticsLogBitmask = statisticsLogOptions;
+
+  if( mStatisticsLogBitmask == PerformanceInterface::LOG_EVERYTHING )
+  {
+    mStatisticsLogBitmask = 0xFFFFFFFF; // enable everything
+  }
+
+  mLogFrequency = logFrequency;
+
+  // currently uses DALI_LOG_PERFORMANCE_STATS_FREQ environment variable to determine to log frequency
+  // if it's not set it will be zero
+  if( mLogFrequency == 0 )
+  {
+    mLogFrequency = DEFAULT_LOG_FREQUENCY;
+  }
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_UPDATE_RENDER, mUpdateStats );
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_UPDATE_RENDER, mRenderStats );
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_EVENT_PROCESS, mEventStats );
+
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+     StatContext* context = *it;
+     context->SetLogFrequency( mLogFrequency );
+  }
+}
+
+void StatContextManager::SetLoggingFrequency( unsigned int logFrequency,
+                                              PerformanceInterface::ContextId contextId  )
+{
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    if( logFrequency == 0 )
+    {
+      logFrequency = DEFAULT_LOG_FREQUENCY;
+    }
+    context->SetLogFrequency( logFrequency );
+  }
+}
+const char* const StatContextManager::GetContextName(PerformanceInterface::ContextId contextId) const
+{
+  StatContext* context = GetContext(contextId);
+  if( context )
+  {
+    return context->GetName();
+  }
+  return "context not found";
+}
+
+const char* const StatContextManager::GetMarkerDescription( PerformanceInterface::MarkerType type, PerformanceInterface::ContextId contextId ) const
+{
+  StatContext* context = GetContext(contextId);
+  if( context )
+  {
+    return context->GetMarkerDescription( type );
+  }
+  return "context not found";
+}
+
+
+StatContext* StatContextManager::GetContext( PerformanceInterface::ContextId contextId ) const
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+
+    if( context->GetId() == contextId )
+    {
+      return context;
+    }
+  }
+
+  return NULL;
+}
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+
diff --git a/adaptors/base/performance-logging/statistics/stat-context-manager.h b/adaptors/base/performance-logging/statistics/stat-context-manager.h
new file mode 100644 (file)
index 0000000..1252eee
--- /dev/null
@@ -0,0 +1,167 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H__
+#define __DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/mutex.h>
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/performance-marker.h>
+#include <base/performance-logging/statistics/stat-context.h>
+#include <base/interfaces/performance-interface.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Class to manage StatContext objects.
+ *
+ * Contains 3 built in contexts for event, update, render.
+ * The application developer can add more using the PerformanceLogger public API
+ *
+ * Example output of 4 contexts ( event, update, render and a custom one):
+ *
+ * Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+ * Update, min 0.29 ms, max 0.91 ms, total (0.5 secs), avg 0.68 ms, std dev 0.15 ms
+ * Render, min 0.33 ms, max 0.97 ms, total (0.6 secs), avg 0.73 ms, std dev 0.17 ms
+ * MyAppTask, min 76.55 ms, max 76.55 ms, total (0.1 secs), avg 76.55 ms, std dev 0.00 ms  (CUSTOM CONTEXT)
+ *
+ */
+class StatContextManager
+{
+
+public:
+
+    /**
+     * @brief Constructor
+     * @param[in] logInterface interface to log statistics to
+     */
+    StatContextManager( StatContextLogInterface& logInterface );
+
+    /**
+     * @brief destructor, not intended as a bass class
+     */
+    ~StatContextManager();
+
+    /**
+     * @brief Add a context
+     * @param[in] name Name of the context to print in console
+     * @param[in] type the type of events to filter ( e.g. event, update, render or custom)
+     * @return The ID to give the context
+     */
+    PerformanceInterface::ContextId AddContext( const char* const name, PerformanceMarker::MarkerFilter type );
+
+    /**
+     * @brief Remove a context
+     * @param[in] contextId id of the context to remove
+     */
+    void RemoveContext(PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief Add an internal marker (e.g. v-sync, update, render markers)
+     * @param[in] marker the marker to add
+     */
+    void AddInternalMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Add a custom marker defined by the application
+     * @param[in] marker the marker to add
+     * @param[in] contextId the context the custom marker is designed for
+     */
+    void AddCustomMarker( const PerformanceMarker& marker , PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief Get the nane of a context
+     * @param[in] contextId id of the context to get the name
+     * @return context name
+     */
+    const char* const GetContextName( PerformanceInterface::ContextId contextId ) const;
+
+    /**
+     * @brief Get the full description of a marker for this context
+     * @param[in] type marker type, for a customer marker this will be either START or END
+     * @param[in] contextId id of the context to get the name
+     * @return marker description in relation to this context
+     */
+    const char* const GetMarkerDescription( PerformanceInterface::MarkerType type, PerformanceInterface::ContextId contextId ) const;
+
+
+    /**
+     * @brief enable / disable logging for a context
+     * @param[in] enable whether to enable logging
+     * @param[in] contextId the context to configure
+     */
+    void EnableLogging( bool enable, PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief set global logging level and frequency.
+     * @param[in] statisticsLogOptions  log options
+     * @param[in] logFrequency frequency in seconds
+     */
+    void SetLoggingLevel( unsigned int statisticsLogOptions, unsigned int logFrequency);
+
+    /**
+     * @brief Set the frequency of logging for an individual context
+     * @param[in] logFrequency log frequency in seconds
+     * @param[in] contextId the context to configure
+     */
+    void SetLoggingFrequency( unsigned int logFrequency, PerformanceInterface::ContextId contextId  );
+
+  private:
+
+    typedef Dali::Vector< StatContext* > StatContexts;
+
+    /**
+     * @brief helper
+     * @param[in] contextId the context to get
+     * @return context
+     */
+    StatContext* GetContext( PerformanceInterface::ContextId contextId ) const;
+
+    Dali::Mutex mDataMutex;                            ///< mutex
+    StatContexts mStatContexts;                        ///< The list of stat contexts
+    StatContextLogInterface& mLogInterface;            ///< Log interface
+
+    PerformanceInterface::ContextId mNextContextId;    ///< The next valid context ID
+
+    // Some defaults contexts
+    PerformanceInterface::ContextId mUpdateStats;    ///< update time statistics
+    PerformanceInterface::ContextId mRenderStats;    ///< render time statistics
+    PerformanceInterface::ContextId mEventStats;     ///< event time statistics
+
+    unsigned int mStatisticsLogBitmask;              ///< statistics log bitmask
+    unsigned int mLogFrequency;                      ///< log frequency
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H__
+
diff --git a/adaptors/base/performance-logging/statistics/stat-context.cpp b/adaptors/base/performance-logging/statistics/stat-context.cpp
new file mode 100644 (file)
index 0000000..de0a4fc
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include "stat-context.h"
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#define TIME_FMT "%0.2f ms"         // 2 decimal places, e.g. 5.34 ms
+#define TOTAL_TIME_FMT "%0.1f secs" // 1 decimal place, e.g. 4.5 seconds
+
+namespace
+{
+const unsigned int MILLISECONDS_PER_SECOND = 1000;    ///< 1000 milliseconds per second
+const char* const UNKNOWN_CONTEXT_NAME = "UNKNOWN_CONTEXT_NAME";
+const unsigned int MICROSECONDS_PER_SECOND = 1000000; ///< 1000000 microseconds per second
+const unsigned int CONTEXT_LOG_SIZE = 120;
+
+}
+
+StatContext::StatContext( unsigned int id,
+                          const char* const contextName,
+                          PerformanceMarker::MarkerFilter contextType,
+                          unsigned int logFrequencySeconds,
+                          StatContextLogInterface& logInterface )
+: mInitialMarker(PerformanceInterface::VSYNC),
+  mName( contextName ),
+  mLogInterface( logInterface ),
+  mNamePlusStart( std::string(contextName) + "_START" ),
+  mNamePlusEnd( std::string(contextName) + "_END" ),
+  mId( id ),
+  mLogFrequencyMicroseconds( logFrequencySeconds * MICROSECONDS_PER_SECOND ),
+  mFilterType( contextType ),
+  mLoggingEnabled( true ),
+  mInitialMarkerSet( false )
+{
+  mTempLogBuffer = new char[ CONTEXT_LOG_SIZE ];
+}
+
+StatContext::~StatContext()
+{
+  delete []mTempLogBuffer;
+}
+unsigned int StatContext::GetId() const
+{
+  return mId;
+}
+
+const char* const StatContext::GetName() const
+{
+  return mName;
+}
+
+const char* const StatContext::GetMarkerDescription( PerformanceInterface::MarkerType type ) const
+{
+  if( type == PerformanceInterface::START )
+  {
+    return mNamePlusStart.c_str();
+  }
+  else if( type == PerformanceInterface::END )
+  {
+    return mNamePlusEnd.c_str();
+  }
+  return UNKNOWN_CONTEXT_NAME;
+}
+void StatContext::SetLogFrequency( unsigned int logFrequencySeconds )
+{
+  mLogFrequencyMicroseconds = logFrequencySeconds * MICROSECONDS_PER_SECOND;
+}
+
+void StatContext::EnableLogging( bool enableLogging )
+{
+  mLoggingEnabled = enableLogging;
+}
+
+void StatContext::ProcessCustomMarker( const PerformanceMarker& marker )
+{
+  // this marker has come from the application PerformanceLogger API
+  RecordMarker( marker);
+}
+
+void StatContext::ProcessInternalMarker( const PerformanceMarker& marker )
+{
+  // this marker has come from DALi internal not the application
+  // see if this context is for update, render or event
+ if( marker.IsFilterEnabled( mFilterType ))
+ {
+   RecordMarker( marker );
+ }
+ // V_SYNC is always processed
+ if( marker.GetType() == PerformanceInterface::VSYNC )
+ {
+   FrameTick( marker );
+ }
+}
+
+void StatContext::RecordMarker( const PerformanceMarker& marker )
+{
+  if( marker.GetEventType() == PerformanceMarker::START_TIMED_EVENT )
+  {
+    mStats.StartTime( marker.GetTimeStamp() );
+  }
+  else if( marker.GetEventType() == PerformanceMarker::END_TIMED_EVENT )
+  {
+    mStats.EndTime( marker.GetTimeStamp() );
+  }
+}
+
+void StatContext::FrameTick( const PerformanceMarker& marker )
+{
+  // wait until we've got some data
+  if( ! mInitialMarkerSet )
+  {
+    mInitialMarker = marker;
+    mInitialMarkerSet = true;
+    return;
+  }
+  // log out every mLogFrequency.
+  // check difference between first and last frame
+  unsigned int microseconds = PerformanceMarker::MicrosecondDiff( mInitialMarker, marker );
+
+  if( microseconds < mLogFrequencyMicroseconds )
+  {
+    return;
+  }
+
+  if( mLoggingEnabled )
+  {
+    LogMarker();
+  }
+  mStats.Reset();             // reset data for statistics
+  mInitialMarkerSet = false;  // need to restart the timer
+
+}
+
+void StatContext::LogMarker()
+{
+  float mean, standardDeviation;
+  mStats.CalculateMean( mean, standardDeviation );
+
+  snprintf( mTempLogBuffer, CONTEXT_LOG_SIZE, "%s, min " TIME_FMT ", max " TIME_FMT ", total (" TOTAL_TIME_FMT "), avg " TIME_FMT ", std dev " TIME_FMT "\n",
+     mName ? mName : UNKNOWN_CONTEXT_NAME,
+     mStats.GetMinTime() * MILLISECONDS_PER_SECOND,
+     mStats.GetMaxTime() * MILLISECONDS_PER_SECOND,
+     mStats.GetTotalTime(),
+     mean * MILLISECONDS_PER_SECOND,
+     standardDeviation * MILLISECONDS_PER_SECOND );
+
+    mLogInterface.LogContextStatistics( mTempLogBuffer );
+
+}
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/adaptors/base/performance-logging/statistics/stat-context.h b/adaptors/base/performance-logging/statistics/stat-context.h
new file mode 100644 (file)
index 0000000..2408905
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_H__
+#define __DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+// INTERNAL INCLUDES
+#include <base/performance-logging/performance-marker.h>
+#include <base/performance-logging/frame-time-stats.h>
+#include <base/interfaces/performance-interface.h>
+#include <base/performance-logging/statistics/stat-context-log-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Stores and prints statistics for a particular logging context.
+ *
+ */
+class StatContext
+{
+
+public:
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] id The ID to give the context
+     * @param[in] contextName Name of the context to print in console
+     * @param[in] contextType the type of events to filter ( e.g. event, update, render or custom)
+     * @param[in] logFrequencySeconds frequency to log in seconds
+     * @param[in] logInterface interface to log out to
+     *
+     */
+    StatContext( unsigned int id,
+                 const char* const contextName,
+                 PerformanceMarker::MarkerFilter contextType,
+                 unsigned int logFrequencySeconds,
+                 StatContextLogInterface& logInterface );
+
+
+    /**
+     * @brief Non-virtual destructor, not intended as a base class
+     */
+    ~StatContext();
+
+    /**
+     * @return Return the context ID
+     */
+    unsigned int GetId() const;
+
+    /**
+     * @return the context name
+     */
+    const char* const GetName() const;
+
+    /**
+     *
+     * For logging we want to output the name of the context with either
+     * START / END appended to the end. E.g. MY_MARKER_START
+     * @param[in] type marker type, for a customer marker this will be either START or END
+     * @return the full description for a marker
+     */
+    const char* const GetMarkerDescription( PerformanceInterface::MarkerType type ) const;
+
+    /**
+     * @brief Set the frequency for logging
+     *
+     * @param[in] logFrequencySeconds The log frequency to set in seconds
+     */
+    void SetLogFrequency( unsigned int logFrequencySeconds );
+
+    /**
+     * @brief enable/disable logging
+     *
+     * @param[in] enableLogging Flag to spePerformancecify enabling/disabling
+     */
+    void EnableLogging( bool enableLogging );
+
+    /**
+     * @brief  Process a custom marker from the application
+     *
+     * @param[in] marker The marker to log
+     */
+    void ProcessCustomMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Process a internal marker from DALi (V_SYNC/ UPDATE /RENDER/ EVENT )
+     *
+     * @param[in] marker The marker to log
+     */
+    void ProcessInternalMarker( const PerformanceMarker& marker );
+
+  private:
+
+    /**
+     * @brief Record marker
+     *
+     * @param[in] marker to record
+     */
+    void RecordMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Called when V-SYNC occurs to indicate a frame tick
+     * @param[in] marker the marker containing a v-sync
+     */
+    void FrameTick( const PerformanceMarker& marker );
+
+    /**
+     * @brief Helper to print to console
+     */
+    void LogMarker();
+
+
+  private:
+
+    StatContext();                                ///< undefined default constructor
+
+    StatContext( const StatContext& );            ///< undefined copy constructor
+
+    StatContext& operator=( const StatContext& ); ///< undefined assignment operator
+
+  private:
+
+    PerformanceMarker mInitialMarker;             ///< Used to store initial time
+    FrameTimeStats mStats;                        ///< Frame time stats to accumulate
+    const char* const mName;                      ///< Name of the context
+    char* mTempLogBuffer;                         ///< Temporary log buffer
+    StatContextLogInterface& mLogInterface;       ///< Log interface
+    const std::string mNamePlusStart;             ///< Name of the context + _START
+    const std::string mNamePlusEnd;                ///< Name of the context + _END
+    unsigned int mId;                             ///< The ID of the context
+    unsigned int mLogFrequencyMicroseconds;       ///< if logging is enabled, what frequency to log out at in micro-seconds
+    PerformanceMarker::MarkerFilter mFilterType;  ///< type of events the context is filtering
+    bool mLoggingEnabled:1;                       ///< Whether to print the log for this context or not
+    bool mInitialMarkerSet:1;                     ///< Whether the initial marker has been set
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/adaptors/base/render-thread.cpp b/adaptors/base/render-thread.cpp
new file mode 100644 (file)
index 0000000..1556f8d
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "render-thread.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/thread-synchronization.h>
+#include <base/environment-options.h>
+#include <base/display-connection.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gRenderLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_RENDER_THREAD");
+#endif
+}
+
+RenderRequest::RenderRequest(RenderRequest::Request type)
+: mRequestType(type)
+{
+}
+
+RenderRequest::Request RenderRequest::GetType()
+{
+  return mRequestType;
+}
+
+ReplaceSurfaceRequest::ReplaceSurfaceRequest()
+: RenderRequest(RenderRequest::REPLACE_SURFACE),
+  mNewSurface( NULL ),
+  mReplaceCompleted(false)
+{
+}
+
+void ReplaceSurfaceRequest::SetSurface(RenderSurface* newSurface)
+{
+  mNewSurface = newSurface;
+}
+
+RenderSurface* ReplaceSurfaceRequest::GetSurface()
+{
+  return mNewSurface;
+}
+
+void ReplaceSurfaceRequest::ReplaceCompleted()
+{
+  mReplaceCompleted = true;
+}
+
+bool ReplaceSurfaceRequest::GetReplaceCompleted()
+{
+  return mReplaceCompleted != 0u;
+}
+
+
+RenderThread::RenderThread( ThreadSynchronization& sync,
+                            AdaptorInternalServices& adaptorInterfaces,
+                            const EnvironmentOptions& environmentOptions )
+: mThreadSynchronization( sync ),
+  mCore( adaptorInterfaces.GetCore() ),
+  mGLES( adaptorInterfaces.GetGlesInterface() ),
+  mEglFactory( &adaptorInterfaces.GetEGLFactoryInterface()),
+  mEGL( NULL ),
+  mThread( NULL ),
+  mEnvironmentOptions( environmentOptions ),
+  mSurfaceReplaced(false)
+{
+  // set the initial values before render thread starts
+  mSurface = adaptorInterfaces.GetRenderSurfaceInterface();
+
+  mDisplayConnection = Dali::DisplayConnection::New();
+}
+
+RenderThread::~RenderThread()
+{
+  if (mDisplayConnection)
+  {
+    delete mDisplayConnection;
+    mDisplayConnection = NULL;
+  }
+
+  DALI_ASSERT_ALWAYS( mThread == NULL && "RenderThread is still alive");
+  mEglFactory->Destroy();
+}
+
+void RenderThread::Start()
+{
+  DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Start()\n");
+
+  // initialise GL and kick off render thread
+  DALI_ASSERT_ALWAYS( !mEGL && "Egl already initialized" );
+
+  // create the render thread, initially we are rendering
+  mThread = new pthread_t();
+  int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
+  DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in RenderThread" );
+
+  if( mSurface )
+  {
+    mSurface->StartRender();
+  }
+}
+
+void RenderThread::Stop()
+{
+  DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Stop()\n");
+
+  if( mSurface )
+  {
+    // Tell surface we have stopped rendering
+    mSurface->StopRender();
+
+    // The surface will be destroyed soon; this pointer will become invalid
+    mSurface = NULL;
+  }
+
+  // shutdown the render thread and destroy the opengl context
+  if( mThread )
+  {
+    // wait for the thread to finish
+    pthread_join(*mThread, NULL);
+
+    delete mThread;
+    mThread = NULL;
+  }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// The following methods are all executed inside render thread !!!
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool RenderThread::Run()
+{
+  DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run\n");
+
+  // Install a function for logging
+  mEnvironmentOptions.InstallLogFunction();
+
+  InitializeEgl();
+
+  Dali::Integration::RenderStatus renderStatus;
+  RenderRequest* request = NULL;
+
+  // Render loop, we stay inside here when rendering
+  while( mThreadSynchronization.RenderReady( request ) )
+  {
+    DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 1 - RenderReady\n");
+
+    // Consume any pending events to avoid memory leaks
+    DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 2 - ConsumeEvents\n");
+    mDisplayConnection->ConsumeEvents();
+
+    // Check if we've got a request from the main thread (e.g. replace surface)
+    if( request )
+    {
+      // Process the request, we should NOT render when we have a request
+      DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Process requests\n");
+      ProcessRequest( request );
+    }
+    else
+    {
+      // No request to process so we render
+      if( PreRender() ) // Returns false if no surface onto which to render
+      {
+        // Render
+        DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 3 - Core.Render()\n");
+
+        mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_START );
+        mCore.Render( renderStatus );
+        mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::RENDER_END );
+
+        // Perform any post-render operations
+        if ( renderStatus.HasRendered() )
+        {
+          DALI_LOG_INFO( gRenderLogFilter, Debug::Verbose, "RenderThread::Run. 4 - PostRender()\n");
+          PostRender();
+        }
+      }
+    }
+
+    request = NULL; // Clear the request if it was set, no need to release memory
+  }
+
+  // Shut down EGL
+  ShutdownEgl();
+
+  // Uninstall the logging function
+  mEnvironmentOptions.UnInstallLogFunction();
+
+  return true;
+}
+
+void RenderThread::InitializeEgl()
+{
+  mEGL = mEglFactory->Create();
+
+  DALI_ASSERT_ALWAYS( mSurface && "NULL surface" );
+
+  // initialize egl & OpenGL
+  mDisplayConnection->InitializeEgl( *mEGL );
+  mSurface->InitializeEgl( *mEGL );
+
+  // create the OpenGL context
+  mEGL->CreateContext();
+
+  // create the OpenGL surface
+  mSurface->CreateEglSurface(*mEGL);
+
+  // Make it current
+  mEGL->MakeContextCurrent();
+
+  // set the initial sync mode
+
+  // tell core it has a context
+  mCore.ContextCreated();
+
+  // check if pixmap is y-inverted
+  mCore.SetPixmapYInverted( mEGL->IsPixmapYInverted() );
+}
+
+void RenderThread::ProcessRequest( RenderRequest* request )
+{
+  if( request != NULL )
+  {
+    switch(request->GetType())
+    {
+      case RenderRequest::REPLACE_SURFACE:
+      {
+        // change the surface
+        ReplaceSurfaceRequest* replaceSurfaceRequest = static_cast<ReplaceSurfaceRequest*>(request);
+        ReplaceSurface( replaceSurfaceRequest->GetSurface() );
+        replaceSurfaceRequest->ReplaceCompleted();
+        mThreadSynchronization.RenderInformSurfaceReplaced();
+        break;
+      }
+    }
+  }
+}
+
+void RenderThread::ReplaceSurface( RenderSurface* newSurface )
+{
+  // This is designed for replacing pixmap surfaces, but should work for window as well
+  // we need to delete the egl surface and renderable (pixmap / window)
+  // Then create a new pixmap/window and new egl surface
+  // If the new surface has a different display connection, then the context will be lost
+  DALI_ASSERT_ALWAYS(newSurface && "NULL surface");
+
+  mDisplayConnection->InitializeEgl(*mEGL);
+
+  newSurface->ReplaceEGLSurface(*mEGL);
+
+  // use the new surface from now on
+  mSurface = newSurface;
+  mSurfaceReplaced = true;
+}
+
+void RenderThread::ShutdownEgl()
+{
+  // inform core of context destruction
+  mCore.ContextDestroyed();
+
+  if( mSurface )
+  {
+    // give a chance to destroy the OpenGL surface that created externally
+    mSurface->DestroyEglSurface( *mEGL );
+  }
+
+  // delete the GL context / egl surface
+  mEGL->TerminateGles();
+}
+
+bool RenderThread::PreRender()
+{
+  bool success( false );
+  if( mSurface )
+  {
+    success = mSurface->PreRender( *mEGL, mGLES );
+  }
+
+  if( success )
+  {
+    mGLES.PreRender();
+  }
+  return success;
+}
+
+void RenderThread::PostRender()
+{
+  // Inform the gl implementation that rendering has finished before informing the surface
+  mGLES.PostRender();
+
+  if( mSurface )
+  {
+    // Inform the surface that rendering this frame has finished.
+    mSurface->PostRender( *mEGL, mGLES, mDisplayConnection, mSurfaceReplaced );
+  }
+  mSurfaceReplaced = false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/render-thread.h b/adaptors/base/render-thread.h
new file mode 100644 (file)
index 0000000..3341e00
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef __DALI_INTERNAL_RENDER_THREAD_H__
+#define __DALI_INTERNAL_RENDER_THREAD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+// INTERNAL INCLUDES
+#include <egl-interface.h>
+#include <render-surface.h> // needed for Dali::RenderSurface
+
+namespace Dali
+{
+
+class RenderSurface;
+class DisplayConnection;
+
+namespace Integration
+{
+class GlAbstraction;
+class Core;
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class AdaptorInternalServices;
+class ThreadSynchronization;
+class EglFactoryInterface;
+class EnvironmentOptions;
+
+class RenderRequest
+{
+public:
+  enum Request
+  {
+    REPLACE_SURFACE, // Request to replace surface
+  };
+
+  /**
+   * Constructor.
+   * @param[in] type The type of the request
+   */
+  RenderRequest( Request type );
+
+  /**
+   * @return the type of the request
+   */
+  Request GetType();
+
+private:
+  Request mRequestType;
+};
+
+class ReplaceSurfaceRequest : public RenderRequest
+{
+public:
+
+  /**
+   * Constructor
+   */
+  ReplaceSurfaceRequest();
+
+  /**
+   * Set the new surface
+   * @param[in] newSurface The new surface to use
+   */
+  void SetSurface(RenderSurface* newSurface);
+
+  /**
+   * @return the new surface
+   */
+  RenderSurface* GetSurface();
+
+  /**
+   * Called when the request has been completed to set the result.
+   */
+  void ReplaceCompleted();
+
+  /**
+   * @return true if the replace has completed.
+   */
+  bool GetReplaceCompleted();
+
+private:
+  RenderSurface* mNewSurface;     ///< The new surface to use.
+  unsigned int mReplaceCompleted; ///< Set to true when the replace has completed.
+};
+
+
+/**
+ * The render-thread is responsible for calling Core::Render() after each update.
+ */
+class RenderThread
+{
+public:
+
+  /**
+   * Create the render-thread; this will not do anything until Start() is called.
+   * @param[in] sync thread synchronization object
+   * @param[in] adaptorInterfaces base adaptor interface
+   * @param[in] environmentOptions environment options
+   */
+  RenderThread( ThreadSynchronization& sync,
+                AdaptorInternalServices& adaptorInterfaces,
+                const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Destructor
+   */
+  ~RenderThread();
+
+public:
+
+  /**
+   * Starts the render-thread
+   */
+  void Start();
+
+  /**
+   * Stops the render-thread
+   */
+  void Stop();
+
+private: // Render thread side helpers
+
+  /**
+   * This method is used by the Render thread for rendering the Core to the screen.
+   * Called from render thread
+   * @return true, if the thread finishes properly.
+   */
+  bool Run();
+
+  /**
+   * Initializes EGL.
+   * Called from render thread
+   */
+  void InitializeEgl();
+
+  /**
+   * Check if main thread made any requests, e.g. ReplaceSurface
+   * Called from render thread
+   */
+  void ProcessRequest( RenderRequest* request );
+
+  /**
+   * Replaces the rendering surface
+   * Used for replacing pixmaps due to resizing
+   * Called from render thread
+   * @param newSurface to use
+   */
+  void ReplaceSurface( RenderSurface* newSurface );
+
+  /**
+   * Shuts down EGL.
+   * Called from render thread
+   */
+  void ShutdownEgl();
+
+  /**
+   * Called before core renders the scene
+   * Called from render thread
+   * @return true if successful and Core::Render should be called.
+   */
+  bool PreRender();
+
+  /**
+   * Called after core has rendered the scene
+   * Called from render thread
+   */
+  void PostRender();
+
+  /**
+   * Helper for the thread calling the entry function.
+   * @param[in] This A pointer to the current RenderThread object
+   */
+  static inline void* InternalThreadEntryFunc( void* This )
+  {
+    ( static_cast<RenderThread*>( This ) )->Run();
+    return NULL;
+  }
+
+private:
+
+  // Undefined
+  RenderThread( const RenderThread& renderThread );
+
+  // Undefined
+  RenderThread& operator=( const RenderThread& renderThread );
+
+private: // Data
+
+  ThreadSynchronization&        mThreadSynchronization;  ///< Used to synchronize the all threads
+  Dali::Integration::Core&      mCore;                   ///< Dali core reference
+  Integration::GlAbstraction&   mGLES;                   ///< GL abstraction reference
+  EglFactoryInterface*          mEglFactory;             ///< Factory class to create EGL implementation
+  EglInterface*                 mEGL;                    ///< Interface to EGL implementation
+  pthread_t*                    mThread;                 ///< render thread
+  RenderSurface*                mSurface;                ///< Current surface
+  Dali::DisplayConnection*      mDisplayConnection;      ///< Display connection
+  const EnvironmentOptions&     mEnvironmentOptions;     ///< Environment options
+  bool                          mSurfaceReplaced;        ///< True when new surface has been initialzed.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_RENDER_THREAD_H__
diff --git a/adaptors/base/thread-controller.cpp b/adaptors/base/thread-controller.cpp
new file mode 100644 (file)
index 0000000..1640c8d
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "thread-controller.h"
+
+// INTERNAL INCLUDES
+#include <base/update-thread.h>
+#include <base/render-thread.h>
+#include <base/thread-synchronization.h>
+#include <base/vsync-notifier.h>
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
+: mAdaptorInterfaces( adaptorInterfaces ),
+  mUpdateThread( NULL ),
+  mRenderThread( NULL ),
+  mVSyncNotifier( NULL ),
+  mThreadSync( NULL ),
+  mNumberOfVSyncsPerRender( 1 )
+{
+  mThreadSync = new ThreadSynchronization( adaptorInterfaces, mNumberOfVSyncsPerRender );
+
+  mUpdateThread = new UpdateThread( *mThreadSync, adaptorInterfaces, environmentOptions );
+
+  mRenderThread = new RenderThread( *mThreadSync, adaptorInterfaces, environmentOptions );
+
+  mVSyncNotifier = new VSyncNotifier( *mThreadSync, adaptorInterfaces, environmentOptions );
+
+  // Set the thread-synchronization interface on the render-surface
+  RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  if( currentSurface )
+  {
+    currentSurface->SetThreadSynchronization( *mThreadSync );
+  }
+}
+
+ThreadController::~ThreadController()
+{
+  delete mVSyncNotifier;
+  delete mRenderThread;
+  delete mUpdateThread;
+  delete mThreadSync;
+}
+
+void ThreadController::Initialize()
+{
+  // Notify the synchronization object before starting the threads
+  mThreadSync->Initialise();
+
+  // We want to the threads to be set up before they start
+  mUpdateThread->Start();
+  mRenderThread->Start();
+  mVSyncNotifier->Start();
+}
+
+void ThreadController::Start()
+{
+  mThreadSync->Start();
+}
+
+void ThreadController::Pause()
+{
+  mThreadSync->Pause();
+}
+
+void ThreadController::Resume()
+{
+  mThreadSync->Resume();
+}
+
+void ThreadController::Stop()
+{
+  // Notify the synchronization object before stopping the threads
+  mThreadSync->Stop();
+
+  mVSyncNotifier->Stop();
+  mUpdateThread->Stop();
+  mRenderThread->Stop();
+}
+
+void ThreadController::RequestUpdate()
+{
+  mThreadSync->UpdateRequest();
+}
+
+void ThreadController::RequestUpdateOnce()
+{
+  // if we are paused, need to allow one update
+  mThreadSync->UpdateOnce();
+}
+
+void ThreadController::ReplaceSurface( RenderSurface* newSurface )
+{
+  // Set the thread-syncronization on the new surface
+  newSurface->SetThreadSynchronization( *mThreadSync );
+
+  // tell render thread to start the replace. This call will block until the replace
+  // has completed.
+  RenderSurface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+
+  // Ensure the current surface releases any locks to prevent deadlock.
+  currentSurface->StopRender();
+
+  mThreadSync->ReplaceSurface( newSurface );
+}
+
+void ThreadController::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender )
+{
+  mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
+  mThreadSync->SetRenderRefreshRate(numberOfVSyncsPerRender);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/thread-controller.h b/adaptors/base/thread-controller.h
new file mode 100644 (file)
index 0000000..0413815
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef __DALI_INTERNAL_UPDATE_RENDER_CONTROLLER_H__
+#define __DALI_INTERNAL_UPDATE_RENDER_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class UpdateThread;
+class RenderThread;
+class VSyncNotifier;
+class ThreadSynchronization;
+class AdaptorInternalServices;
+class EnvironmentOptions;
+
+/**
+ * Class to control all the threads.
+ */
+class ThreadController
+{
+public:
+
+  /**
+   * Constructor
+   */
+  ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non virtual destructor. Not intended as base class.
+   */
+  ~ThreadController();
+
+  /**
+   * Initializes the thread controller
+   */
+  void Initialize();
+
+  /**
+   * @copydoc Dali::Adaptor::Start()
+   */
+  void Start();
+
+  /**
+   * @copydoc Dali::Adaptor::Pause()
+   */
+  void Pause();
+
+  /**
+   * @copydoc Dali::Adaptor::Resume()
+   */
+  void Resume();
+
+  /**
+   * @copydoc Dali::Adaptor::Stop()
+   */
+  void Stop();
+
+  /**
+   * Called by the adaptor when core requires another update
+   */
+  void RequestUpdate();
+
+  /**
+   * Called by the adaptor when core requires one update
+   * If Adaptor is paused, we do one update and return to pause
+   */
+  void RequestUpdateOnce();
+
+  /**
+   * Replaces the surface.
+   * @param surface new surface
+   */
+  void ReplaceSurface( RenderSurface* surface );
+
+  /**
+   * @copydoc Dali::Adaptor::SetRenderRefreshRate()
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+private:
+
+  // Undefined copy constructor.
+  ThreadController( const ThreadController& );
+
+  // Undefined assignment operator.
+  ThreadController& operator=( const ThreadController& );
+
+  AdaptorInternalServices&     mAdaptorInterfaces;
+
+  UpdateThread*                mUpdateThread;     ///< The update-thread owned by ThreadController
+  RenderThread*                mRenderThread;     ///< The render-thread owned by ThreadController
+  VSyncNotifier*               mVSyncNotifier;    ///< The vsync-thread owned by ThreadController
+  ThreadSynchronization*       mThreadSync;       ///< Used to synchronize all the threads; owned by ThreadController
+  unsigned int                 mNumberOfVSyncsPerRender; ///< Frame skipping count
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_UPDATE_RENDER_CONTROLLER_H__
diff --git a/adaptors/base/thread-synchronization-debug.h b/adaptors/base/thread-synchronization-debug.h
new file mode 100644 (file)
index 0000000..8edf4b3
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
+#define __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// Uncomment next line for FULL logging of the ThreadSynchronization class in release mode
+//#define RELEASE_BUILD_LOGGING
+
+#ifdef DEBUG_ENABLED
+
+#define ENABLE_LOG_IN_COLOR
+#define ENABLE_VSYNC_COUNTER_LOGGING
+#define ENABLE_UPDATE_COUNTER_LOGGING
+#define ENABLE_VSYNC_THREAD_LOGGING
+#define ENABLE_UPDATE_THREAD_LOGGING
+#define ENABLE_RENDER_THREAD_LOGGING
+#define ENABLE_EVENT_LOGGING
+
+#define DEBUG_LEVEL_COUNTER     Debug::Verbose
+#define DEBUG_LEVEL_VSYNC       Debug::General
+#define DEBUG_LEVEL_UPDATE      Debug::General
+#define DEBUG_LEVEL_RENDER      Debug::General
+#define DEBUG_LEVEL_EVENT       Debug::Concise
+
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_THREAD_SYNC" );
+
+#define LOG_THREAD_SYNC(level, color, format, args...) \
+  DALI_LOG_INFO( gLogFilter, level, "%s" format "%s\n", color, ## args, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE(color) \
+  Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s%s", color, __FUNCTION__, COLOR_CLEAR ); \
+  if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s", __FUNCTION__ ); }
+
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...) \
+  Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s: " format "%s", color, __FUNCTION__, ## args, COLOR_CLEAR ); \
+  if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s: " format, __FUNCTION__, ## args ); }
+
+#elif defined( RELEASE_BUILD_LOGGING )
+
+#define ENABLE_LOG_IN_COLOR
+#define ENABLE_VSYNC_COUNTER_LOGGING
+#define ENABLE_UPDATE_COUNTER_LOGGING
+#define ENABLE_VSYNC_THREAD_LOGGING
+#define ENABLE_UPDATE_THREAD_LOGGING
+#define ENABLE_RENDER_THREAD_LOGGING
+#define ENABLE_EVENT_LOGGING
+
+#define DEBUG_LEVEL_COUNTER     0
+#define DEBUG_LEVEL_VSYNC       0
+#define DEBUG_LEVEL_UPDATE      0
+#define DEBUG_LEVEL_RENDER      0
+#define DEBUG_LEVEL_EVENT       0
+
+#define LOG_THREAD_SYNC(level, color, format, args...) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s" format "%s\n", color, ## args, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE(color) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s%s\n", color, __FUNCTION__, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s: " format "%s\n", color, __FUNCTION__, ## args, COLOR_CLEAR )
+
+#else
+
+#define LOG_THREAD_SYNC(level, color, format, args...)
+#define LOG_THREAD_SYNC_TRACE(color)
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, args...)
+
+#endif // DEBUG_ENABLED
+
+#ifdef ENABLE_LOG_IN_COLOR
+#define COLOR_RED            "\033[31m"
+#define COLOR_YELLOW         "\033[33m"
+#define COLOR_BLUE           "\033[34m"
+#define COLOR_LIGHT_RED      "\033[91m"
+#define COLOR_LIGHT_YELLOW   "\033[93m"
+#define COLOR_LIGHT_BLUE     "\033[94m"
+#define COLOR_WHITE          "\033[97m"
+#define COLOR_CLEAR          "\033[0m"
+#else
+#define COLOR_RED
+#define COLOR_YELLOW
+#define COLOR_BLUE
+#define COLOR_LIGHT_RED
+#define COLOR_LIGHT_YELLOW
+#define COLOR_LIGHT_BLUE
+#define COLOR_WHITE
+#define COLOR_CLEAR
+#endif
+
+#ifdef ENABLE_VSYNC_COUNTER_LOGGING
+#define LOG_VSYNC_COUNTER_VSYNC(format, args...)    LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_RED, "%s: " format, __FUNCTION__, ## args)
+#define LOG_VSYNC_COUNTER_UPDATE(format, args...)   LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_YELLOW, "%s: " format, __FUNCTION__, ## args)
+#else
+#define LOG_VSYNC_COUNTER_VSYNC(format, args...)
+#define LOG_VSYNC_COUNTER_UPDATE(format, args...)
+#endif
+
+#ifdef ENABLE_UPDATE_COUNTER_LOGGING
+#define LOG_UPDATE_COUNTER_UPDATE(format, args...)  LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_YELLOW, "%s: " format, __FUNCTION__, ## args)
+#define LOG_UPDATE_COUNTER_RENDER(format, args...)  LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_BLUE, "%s: " format, __FUNCTION__, ## args)
+#else
+#define LOG_UPDATE_COUNTER_UPDATE(format, args...)
+#define LOG_UPDATE_COUNTER_RENDER(format, args...)
+#endif
+
+#ifdef ENABLE_VSYNC_THREAD_LOGGING
+#define LOG_VSYNC(format, args...)             LOG_THREAD_SYNC(DEBUG_LEVEL_VSYNC, COLOR_RED, "%s: " format, __FUNCTION__, ## args)
+#define LOG_VSYNC_TRACE                        LOG_THREAD_SYNC_TRACE(COLOR_RED)
+#define LOG_VSYNC_TRACE_FMT(format, args...)   LOG_THREAD_SYNC_TRACE_FMT(COLOR_RED, format, ## args)
+#else
+#define LOG_VSYNC(format, args...)
+#define LOG_VSYNC_TRACE
+#define LOG_VSYNC_TRACE_FMT(format, args...)
+#endif
+
+#ifdef ENABLE_UPDATE_THREAD_LOGGING
+#define LOG_UPDATE(format, args...)            LOG_THREAD_SYNC(DEBUG_LEVEL_UPDATE, COLOR_YELLOW, "%s: " format, __FUNCTION__, ## args)
+#define LOG_UPDATE_TRACE                       LOG_THREAD_SYNC_TRACE(COLOR_YELLOW)
+#define LOG_UPDATE_TRACE_FMT(format, args...)  LOG_THREAD_SYNC_TRACE_FMT(COLOR_YELLOW, format, ## args)
+#else
+#define LOG_UPDATE(format, args...)
+#define LOG_UPDATE_TRACE
+#define LOG_UPDATE_TRACE_FMT(format, args...)
+#endif
+
+#ifdef ENABLE_RENDER_THREAD_LOGGING
+#define LOG_RENDER(format, args...)            LOG_THREAD_SYNC(DEBUG_LEVEL_RENDER, COLOR_BLUE, "%s: " format, __FUNCTION__, ## args)
+#define LOG_RENDER_TRACE                       LOG_THREAD_SYNC_TRACE(COLOR_BLUE)
+#define LOG_RENDER_TRACE_FMT(format, args...)  LOG_THREAD_SYNC_TRACE_FMT(COLOR_BLUE, format, ## args)
+#else
+#define LOG_RENDER(format, args...)
+#define LOG_RENDER_TRACE
+#define LOG_RENDER_TRACE_FMT(format, args...)
+#endif
+
+#ifdef ENABLE_EVENT_LOGGING
+#define LOG_EVENT(format, args...)             LOG_THREAD_SYNC(DEBUG_LEVEL_EVENT, COLOR_WHITE, "%s: " format, __FUNCTION__, ## args)
+#define LOG_EVENT_TRACE                        LOG_THREAD_SYNC_TRACE(COLOR_WHITE)
+#define LOG_EVENT_TRACE_FMT(format, args...)   LOG_THREAD_SYNC_TRACE_FMT(COLOR_WHITE, format, ## args)
+#else
+#define LOG_EVENT(format, args...)
+#define LOG_EVENT_TRACE
+#define LOG_EVENT_TRACE_FMT(format, args...)
+#endif
+} // unnamed namespace
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_THREAD_SYNCHRONIZATION_DEBUG_H__
diff --git a/adaptors/base/thread-synchronization.cpp b/adaptors/base/thread-synchronization.cpp
new file mode 100644 (file)
index 0000000..875fb3f
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "thread-synchronization.h"
+
+// INTERNAL INCLUDES
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/thread-synchronization-debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int TIME_PER_FRAME_IN_MICROSECONDS = 16667;
+const int TOTAL_THREAD_COUNT = 3;
+const unsigned int TRUE = 1u;
+const unsigned int FALSE = 0u;
+} // unnamed namespace
+
+ThreadSynchronization::ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender)
+: mFrameTime( adaptorInterfaces.GetPlatformAbstractionInterface() ),
+  mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
+  mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
+  mReplaceSurfaceRequest(),
+  mUpdateThreadWaitCondition(),
+  mRenderThreadWaitCondition(),
+  mVSyncThreadWaitCondition(),
+  mEventThreadWaitCondition(),
+  mMaximumUpdateCount( adaptorInterfaces.GetCore().GetMaximumUpdateCount()),
+  mNumberOfVSyncsPerRender( numberOfVSyncsPerRender ),
+  mTryToSleepCount( 0u ),
+  mState( State::STOPPED ),
+  mVSyncAheadOfUpdate( 0u ),
+  mUpdateAheadOfRender( 0u ),
+  mNumberOfThreadsStarted( 0u ),
+  mUpdateThreadResuming( FALSE ),
+  mVSyncThreadRunning( FALSE ),
+  mVSyncThreadStop( FALSE ),
+  mRenderThreadStop( FALSE ),
+  mRenderThreadReplacingSurface( FALSE ),
+  mRenderThreadPostRendering( FALSE ),
+  mEventThreadSurfaceReplaced( FALSE ),
+  mVSyncThreadInitialised( FALSE ),
+  mRenderThreadInitialised( FALSE ),
+  mRenderThreadSurfaceReplaced( FALSE )
+{
+}
+
+ThreadSynchronization::~ThreadSynchronization()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EVENT THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::Initialise()
+{
+  LOG_EVENT_TRACE;
+
+  ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+  if( mState == State::STOPPED )
+  {
+    LOG_EVENT( "INITIALISING" );
+    mState = State::INITIALISING;
+  }
+}
+
+void ThreadSynchronization::Start()
+{
+  LOG_EVENT_TRACE;
+
+  bool start = false;
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( mState == State::INITIALISING )
+    {
+      start = true;
+    }
+  }
+
+  // Not atomic, but does not matter here as we just want to ensure we only start from State::INITIALISING
+  if( start )
+  {
+    LOG_EVENT( "STARTING" );
+    mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
+
+    {
+      ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
+      while( mNumberOfThreadsStarted < TOTAL_THREAD_COUNT )
+      {
+        mEventThreadWaitCondition.Wait( lock );
+      }
+    }
+
+    {
+      ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+      mState = State::RUNNING;
+    }
+    mUpdateThreadWaitCondition.Notify();
+  }
+}
+
+void ThreadSynchronization::Stop()
+{
+  LOG_EVENT_TRACE;
+
+  bool stop = false;
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( mState != State::STOPPED )
+    {
+      stop = true;
+      mState = State::STOPPED;
+    }
+  }
+
+  // Not atomic, but does not matter here as we just want to ensure we do not stop more than once
+  if( stop )
+  {
+    LOG_EVENT( "STOPPING" );
+
+    // Notify update-thread so that it continues and sets up the other threads to stop as well
+    mUpdateThreadWaitCondition.Notify();
+
+    mFrameTime.Suspend();
+  }
+}
+
+void ThreadSynchronization::Pause()
+{
+  LOG_EVENT_TRACE;
+
+  bool addPerformanceMarker = false;
+  {
+    // Only pause if we're RUNNING or SLEEPING
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( ( mState == State::RUNNING ) ||
+        ( mState == State::SLEEPING ) )
+    {
+      LOG_EVENT( "PAUSING" );
+
+      mState = State::PAUSED;
+
+      mUpdateThreadResuming = FALSE;
+
+      mFrameTime.Suspend();
+
+      addPerformanceMarker = true;
+    }
+  }
+
+  if( addPerformanceMarker )
+  {
+    // Can lock so we do not want to have a lock when calling this to avoid deadlocks
+    AddPerformanceMarker( PerformanceInterface::PAUSED );
+  }
+}
+
+void ThreadSynchronization::Resume()
+{
+  LOG_EVENT_TRACE;
+
+  // Only resume if we're PAUSED
+  bool resume = false;
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( mState == State::PAUSED )
+    {
+      resume = true;
+      mState = State::RUNNING;
+      mUpdateThreadResuming = TRUE;
+    }
+  }
+
+  // Not atomic, but does not matter here as we just want to ensure we only resume if we're paused
+  if( resume )
+  {
+    LOG_EVENT( "RESUMING" );
+
+    mFrameTime.Resume();
+
+    // Start up Update thread again
+    mUpdateThreadWaitCondition.Notify();
+
+    // Can lock so we do not want to have a lock when calling this to avoid deadlocks
+    AddPerformanceMarker( PerformanceInterface::RESUME);
+  }
+}
+
+void ThreadSynchronization::UpdateRequest()
+{
+  LOG_EVENT_TRACE;
+
+  bool update = false;
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( mState == State::SLEEPING )
+    {
+      mState = State::RUNNING;
+      update = true;
+    }
+    mTryToSleepCount = 0;
+  }
+
+  if( update )
+  {
+    LOG_EVENT( "UPDATE REQUEST" );
+    mUpdateThreadWaitCondition.Notify();
+  }
+}
+
+void ThreadSynchronization::UpdateOnce()
+{
+  LOG_EVENT_TRACE;
+  LOG_EVENT( "UPDATE ONCE" );
+
+  // If we're sleeping then change state to running as this will also wake up the v-sync-thread
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    if( mState == State::SLEEPING )
+    {
+      mState = State::RUNNING;
+    }
+  }
+
+  mUpdateThreadWaitCondition.Notify();
+}
+
+void ThreadSynchronization::ReplaceSurface( RenderSurface* newSurface )
+{
+  LOG_EVENT_TRACE;
+
+  State::Type previousState( State::STOPPED );
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    previousState = mState;
+    mState = State::REPLACING_SURFACE;
+  }
+
+  {
+    ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
+    mEventThreadSurfaceReplaced = FALSE;
+  }
+
+  {
+    ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+    mReplaceSurfaceRequest.SetSurface( newSurface );
+    mRenderThreadReplacingSurface = TRUE;
+  }
+
+  // Notify the RenderThread in case it's waiting
+  mRenderThreadWaitCondition.Notify();
+
+  {
+    ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
+
+    // Wait for RenderThread to replace the surface
+    while( ! mEventThreadSurfaceReplaced )
+    {
+      LOG_EVENT( "Waiting for Surface to be Replaced" );
+
+      mEventThreadWaitCondition.Wait( lock );
+    }
+  }
+
+  {
+    ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+    mState = previousState;
+  }
+  mUpdateThreadWaitCondition.Notify();
+}
+
+void ThreadSynchronization::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+  LOG_EVENT_TRACE;
+  LOG_EVENT( "SET RENDER REFRESH RATE" );
+
+  mNumberOfVSyncsPerRender = numberOfVSyncsPerRender;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UPDATE THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ThreadSynchronization::UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
+{
+  LOG_UPDATE_TRACE;
+
+  State::Type state = State::STOPPED;
+  {
+    ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+    state = mState;
+  }
+
+  switch( state )
+  {
+    case State::STOPPED:
+    {
+      StopAllThreads();
+      return false; // Stop update-thread
+    }
+
+    case State::INITIALISING:
+    {
+      UpdateInitialising();
+      break;
+    }
+
+    case State::PAUSED:
+    {
+      LOG_UPDATE_TRACE_FMT( "PAUSED" );
+
+      // Just pause the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
+      PauseVSyncThread();
+    }
+    // No break, fall through
+
+    case State::RUNNING:
+    {
+      LOG_UPDATE_TRACE_FMT( "RUNNING" );
+
+      if( IsUpdateThreadResuming() )
+      {
+        LOG_UPDATE( "Restarting VSyncThread" );
+
+        {
+          ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+          mUpdateThreadResuming = FALSE;
+        }
+
+        // Restart the VSyncThread, locks so we shouldn't have a scoped-lock when calling this
+        RunVSyncThread();
+      }
+
+      if( notifyEvent )
+      {
+        LOG_UPDATE( "Notify Event Thread" );
+
+        // Do the notifications first so the event thread can start processing them
+        // Tell the event-thread to wake up (if asleep) and send a notification event to Core
+        mNotificationTrigger.Trigger();
+      }
+
+      // Inform render thread
+      {
+        ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+        ++mUpdateAheadOfRender;
+        LOG_UPDATE_COUNTER_UPDATE( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
+      }
+      mRenderThreadWaitCondition.Notify();
+
+      // Wait if we've reached the maximum-ahead-of-render count.
+      while( MaximumUpdateAheadOfRenderReached() )
+      {
+        LOG_UPDATE( "Maximum Update Ahead of Render: WAIT" );
+
+        mRenderThreadWaitCondition.Notify(); // Notify the render thread in case it was waiting
+
+        {
+          // Ensure we did not stop while we were waiting previously.
+          ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+          if( mState == State::STOPPED )
+          {
+            break; // Break out of while loop
+          }
+          mUpdateThreadWaitCondition.Wait( updateLock );
+        }
+      }
+
+      // Ensure we have had at least 1 V-Sync before we continue
+      // Ensure we didn't stop while we were previously waiting
+      {
+        ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+        if( ( mState != State::STOPPED ) &&
+            ( mVSyncAheadOfUpdate == 0 ) &&
+            ( !mUpdateThreadResuming ) ) // Ensure we don't wait if the update-thread is JUST resuming
+        {
+          LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d) WAIT", mVSyncAheadOfUpdate );
+          mUpdateThreadWaitCondition.Wait( updateLock );
+        }
+        else
+        {
+          LOG_VSYNC_COUNTER_UPDATE( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
+        }
+        mVSyncAheadOfUpdate = 0;
+      }
+
+      // Try to sleep if we do not require any more updates
+      UpdateTryToSleep( runUpdate );
+
+      break;
+    }
+
+    case State::SLEEPING:
+    case State::REPLACING_SURFACE:
+    {
+      break;
+    }
+  }
+
+  // Ensure we didn't stop while we were waiting
+  if( IsUpdateThreadStopping() )
+  {
+    // Locks so we shouldn't have a scoped-lock when calling this
+    StopAllThreads();
+    return false; // Stop update-thread
+  }
+
+  // Just wait if we're replacing the surface as the render-thread is busy
+  UpdateWaitIfReplacingSurface();
+
+  mFrameTime.PredictNextSyncTime( lastFrameDeltaSeconds, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds );
+
+  return true; // Keep update-thread running
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// RENDER THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ThreadSynchronization::RenderReady( RenderRequest*& requestPtr )
+{
+  LOG_RENDER_TRACE;
+
+  if( ! IsRenderThreadReplacingSurface() ) // Call to this function locks so should not be called if we have a scoped-lock
+  {
+    if( ! mRenderThreadInitialised )
+    {
+      LOG_RENDER( "Initialised" );
+
+      mRenderThreadInitialised = TRUE;
+
+      // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
+      NotifyThreadInitialised();
+    }
+    else
+    {
+      if( mRenderThreadSurfaceReplaced )
+      {
+        mRenderThreadSurfaceReplaced = FALSE;
+      }
+      else
+      {
+        // decrement update-ahead-of-render
+        ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
+        --mUpdateAheadOfRender;
+      }
+    }
+
+    // Check if we've had an update, if we haven't then we just wait
+    // Ensure we do not wait if we're supposed to stop
+    {
+      ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
+      if( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop )
+      {
+        do
+        {
+          LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d) WAIT", mUpdateAheadOfRender );
+          mRenderThreadWaitCondition.Wait( renderLock );
+        } while( mUpdateAheadOfRender <= 0 && ! mRenderThreadStop && ! mRenderThreadReplacingSurface );
+      }
+      else
+      {
+        LOG_UPDATE_COUNTER_RENDER( "updateAheadOfRender(%d)", mUpdateAheadOfRender );
+      }
+    }
+  }
+  else
+  {
+    LOG_RENDER( "Just Rendered, now Replacing surface" );
+
+    // ... also decrement update-ahead-of-render
+    ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
+    --mUpdateAheadOfRender;
+  }
+
+  // We may have been asked to replace the surface while we were waiting so check again here
+  if( IsRenderThreadReplacingSurface() )
+  {
+    // Replacing surface
+    LOG_RENDER( "REPLACE SURFACE" );
+
+    ConditionalWait::ScopedLock renderLock( mRenderThreadWaitCondition );
+    requestPtr = &mReplaceSurfaceRequest;
+    mRenderThreadReplacingSurface = FALSE;
+    mRenderThreadSurfaceReplaced = FALSE;
+  }
+
+  return IsRenderThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
+}
+
+void ThreadSynchronization::RenderInformSurfaceReplaced()
+{
+  LOG_RENDER_TRACE;
+
+  mRenderThreadSurfaceReplaced = TRUE;
+  {
+    ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
+    mEventThreadSurfaceReplaced = TRUE;
+  }
+  mEventThreadWaitCondition.Notify();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// V-SYNC THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ThreadSynchronization::VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender )
+{
+  LOG_VSYNC_TRACE;
+
+  // Ensure we do not process an invalid v-sync
+  if( validSync )
+  {
+    {
+      ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
+      if( numberOfVSyncsPerRender != mNumberOfVSyncsPerRender )
+      {
+        numberOfVSyncsPerRender = mNumberOfVSyncsPerRender; // save it back
+        mFrameTime.SetMinimumFrameTimeInterval( mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS );
+      }
+
+      mFrameTime.SetSyncTime( frameNumber );
+    }
+
+    if( ! mVSyncThreadInitialised )
+    {
+      LOG_VSYNC( "Initialised" );
+
+      mVSyncThreadInitialised = TRUE;
+
+      // Notify event thread that this thread is up and running, this locks so we should have a scoped-lock
+      NotifyThreadInitialised();
+    }
+    else
+    {
+      // Increment v-sync-ahead-of-update count and inform update-thread
+      {
+        ConditionalWait::ScopedLock lock( mUpdateThreadWaitCondition );
+        ++mVSyncAheadOfUpdate;
+        LOG_VSYNC_COUNTER_VSYNC( " vSyncAheadOfUpdate(%d)", mVSyncAheadOfUpdate );
+      }
+      mUpdateThreadWaitCondition.Notify();
+    }
+
+    // Ensure update-thread has set us to run before continuing
+    // Ensure we do not wait if we're supposed to stop
+    {
+      ConditionalWait::ScopedLock vSyncLock( mVSyncThreadWaitCondition );
+      while( ! mVSyncThreadRunning && ! mVSyncThreadStop )
+      {
+        LOG_VSYNC( "WAIT" );
+        mVSyncThreadWaitCondition.Wait( vSyncLock );
+      }
+    }
+  }
+  else
+  {
+    LOG_VSYNC( "INVALID SYNC" );
+
+    // Later we still check if the v-sync thread is supposed to keep running so we can still stop the thread if we are supposed to
+  }
+
+  return IsVSyncThreadRunning(); // Call to this function locks so should not be called if we have a scoped-lock
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// POST RENDERING: EVENT THREAD
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::PostRenderComplete()
+{
+  LOG_EVENT_TRACE;
+
+  {
+    ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+    mRenderThreadPostRendering = FALSE;
+  }
+  mRenderThreadWaitCondition.Notify();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// POST RENDERING: RENDER THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::PostRenderStarted()
+{
+  LOG_RENDER_TRACE;
+
+  ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+  mRenderThreadPostRendering = TRUE;
+}
+
+void ThreadSynchronization::PostRenderWaitForCompletion()
+{
+  LOG_RENDER_TRACE;
+
+  ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+  while( mRenderThreadPostRendering &&
+         ! mRenderThreadReplacingSurface ) // We should NOT wait if we're replacing the surface
+  {
+    LOG_RENDER( "WAIT" );
+    mRenderThreadWaitCondition.Wait( lock );
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ALL THREADS: Performance Marker
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::AddPerformanceMarker( PerformanceInterface::MarkerType type )
+{
+  if( mPerformanceInterface )
+  {
+    mPerformanceInterface->AddMarker( type );
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// PRIVATE METHODS
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Called by ALL Threads
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::NotifyThreadInitialised()
+{
+  {
+    ConditionalWait::ScopedLock lock( mEventThreadWaitCondition );
+    ++mNumberOfThreadsStarted;
+  }
+  mEventThreadWaitCondition.Notify();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Called by Update Thread
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void ThreadSynchronization::UpdateInitialising()
+{
+  LOG_UPDATE_TRACE;
+
+  // Notify event thread that this thread is up and running, locks so we shouldn't have a scoped-lock when calling this
+  NotifyThreadInitialised();
+
+  // Wait for first thread-sync point
+  {
+    ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+
+    while( mState == State::INITIALISING )
+    {
+      mUpdateThreadWaitCondition.Wait( updateLock );
+    }
+  }
+
+  // Locks so we shouldn't have a scoped-lock when calling this
+  RunVSyncThread();
+}
+
+void ThreadSynchronization::UpdateTryToSleep( bool runUpdate )
+{
+  LOG_UPDATE_TRACE;
+
+  if( ! runUpdate &&
+      ! IsUpdateThreadResuming() ) // Locks so we shouldn't have a lock, we shouldn't try to sleep if we're JUST resuming
+  {
+    LOG_UPDATE( "TryToSleep" );
+
+    if( ++mTryToSleepCount >= 3 )
+    {
+      LOG_UPDATE( "Going to sleep" );
+
+      // Locks so we shouldn't have a scoped-lock when calling this
+      PauseVSyncThread();
+
+      // Render thread will automatically wait as it relies on update-ahead-of-render count
+
+      // Change the state
+      {
+        ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+
+        // Ensure we weren't stopped while we have been processing
+        if( mState != State::STOPPED )
+        {
+          mState = State::SLEEPING;
+        }
+      }
+
+      // Inform FrameTime that we're going to sleep
+      mFrameTime.Sleep();
+
+      // Wait while we're SLEEPING
+      {
+        ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+        while( mState == State::SLEEPING )
+        {
+          mUpdateThreadWaitCondition.Wait( updateLock );
+        }
+      }
+
+      ////////////////////////
+      // WAKE UP
+      ////////////////////////
+
+      LOG_UPDATE( "Waking Up" );
+
+      // Clear V-Sync-ahead-of-update-count
+      {
+        ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+        mVSyncAheadOfUpdate = 0;
+      }
+
+      // Restart the v-sync-thread, locks so we shouldn't have a scoped-lock
+      RunVSyncThread();
+
+      // Reset try-to-sleep count
+      mTryToSleepCount = 0;
+
+      // Inform frame timer that we've woken up
+      mFrameTime.WakeUp();
+    }
+  }
+  else
+  {
+    mTryToSleepCount = 0;
+  }
+}
+
+void ThreadSynchronization::UpdateWaitIfReplacingSurface()
+{
+  bool replacingSurface = false;
+  {
+    ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+    replacingSurface = ( mState == State::REPLACING_SURFACE );
+  }
+  while( replacingSurface )
+  {
+    LOG_UPDATE_TRACE_FMT( "REPLACING SURFACE" );
+
+    // Locks so should not be called while we have a scoped-lock
+    PauseVSyncThread();
+
+    // One last check before we actually wait in case the state has changed since we checked earlier
+    {
+      ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+      replacingSurface = ( mState == State::REPLACING_SURFACE );
+      if( replacingSurface )
+      {
+        mUpdateThreadWaitCondition.Wait( updateLock );
+      }
+    }
+
+    {
+      ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+      mVSyncAheadOfUpdate = 0;
+    }
+
+    // Locks so should not be called while we have a scoped-lock
+    RunVSyncThread();
+  }
+}
+
+bool ThreadSynchronization::IsUpdateThreadResuming()
+{
+  ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+  return mUpdateThreadResuming;
+}
+
+bool ThreadSynchronization::IsUpdateThreadStopping()
+{
+  ConditionalWait::ScopedLock updateLock( mUpdateThreadWaitCondition );
+  return ( mState == State::STOPPED );
+}
+
+bool ThreadSynchronization::MaximumUpdateAheadOfRenderReached()
+{
+  ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+  return mUpdateAheadOfRender >= mMaximumUpdateCount;
+}
+
+void ThreadSynchronization::StopAllThreads()
+{
+  LOG_UPDATE_TRACE;
+
+  // Lock so we shouldn't have a scoped-lock when calling these methods
+  StopVSyncThread();
+  StopRenderThread();
+}
+
+void ThreadSynchronization::RunVSyncThread()
+{
+  {
+    ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
+    mVSyncThreadRunning = TRUE;
+  }
+  mVSyncThreadWaitCondition.Notify();
+}
+
+void ThreadSynchronization::PauseVSyncThread()
+{
+  ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
+  mVSyncThreadRunning = FALSE;
+}
+
+void ThreadSynchronization::StopVSyncThread()
+{
+  {
+    ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
+    mVSyncThreadStop = TRUE;
+  }
+  mVSyncThreadWaitCondition.Notify();
+}
+
+void ThreadSynchronization::StopRenderThread()
+{
+  {
+    ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+    mRenderThreadStop = TRUE;
+  }
+  mRenderThreadWaitCondition.Notify();
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Called by V-Sync Thread
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ThreadSynchronization::IsVSyncThreadRunning()
+{
+  ConditionalWait::ScopedLock lock( mVSyncThreadWaitCondition );
+  return ! mVSyncThreadStop;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Called by Render Thread
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool ThreadSynchronization::IsRenderThreadRunning()
+{
+  ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+  return ! mRenderThreadStop;
+}
+
+bool ThreadSynchronization::IsRenderThreadReplacingSurface()
+{
+  ConditionalWait::ScopedLock lock( mRenderThreadWaitCondition );
+  return mRenderThreadReplacingSurface;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/thread-synchronization.h b/adaptors/base/thread-synchronization.h
new file mode 100644 (file)
index 0000000..940864a
--- /dev/null
@@ -0,0 +1,429 @@
+#ifndef __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
+#define __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <integration-api/thread-synchronization-interface.h>
+#include <base/interfaces/performance-interface.h>
+#include <base/conditional-wait.h>
+#include <trigger-event-interface.h>
+#include <base/frame-time.h>
+#include <base/render-thread.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class AdaptorInternalServices;
+
+/**
+ * This object is used to synchronize the update, render and vsync threads.
+ * The Core::GetMaximumUpdateCount() method determines how many frames may be prepared, ahead of the rendering.
+ * For example if the maximum update count is 2, then Core::Update() for frame N+1 may be processed whilst frame N is being rendered.
+ * However the Core::Update() for frame N+2 may not be called, until the Core::Render() method for frame N has returned.
+ *
+ */
+class ThreadSynchronization : public Dali::ThreadSynchronizationInterface
+{
+public:
+
+  /**
+   * Create an update/render synchronization object.
+   * @param[in] adaptorInterfaces base adaptor interface
+   * @param[in] numberOfVSyncsPerRender The number of frames per render
+  */
+  ThreadSynchronization( AdaptorInternalServices& adaptorInterfaces, unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * Non virtual destructor. Not intended as base class.
+   */
+  ~ThreadSynchronization();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Event Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Initialises the ThreadSynchronisation class. The expectation is that this function will be
+   * called when all threads are about to be set up and that Start will be called when
+   * the the scene is actually prepared and ready to be displayed. This way our first update
+   * will have the actual scene we require.
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void Initialise();
+
+  /**
+   * Starts running all threads. This waits until all threads are up and running.
+   *
+   * @pre A call to Initialise has been made.
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void Start();
+
+  /**
+   * Stop the threads.
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void Stop();
+
+  /**
+   * Pause the controller (and threads).
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void Pause();
+
+  /**
+   * Resume the controller (and threads).
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void Resume();
+
+  /**
+   * Wake update thread if sleeping. If the update thread is not sleeping
+   * this becomes a no-op.
+   * Called when an update is requested by Core.
+   * i.e. when a batch of messages have been queued for the next update.
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void UpdateRequest();
+
+  /**
+   * Update once (even if paused)
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void UpdateOnce();
+
+  /**
+   * Inform the render thread that there is a new surface, and that
+   * it should replace the current surface.
+   *
+   * @param[in] newSurface The new surface for rendering.
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void ReplaceSurface( RenderSurface* newSurface );
+
+  /**
+   * Set the refresh rate for rendering
+   *
+   * @param[in] numberOfVSyncsPerRender The number of vsync frames per render
+   *
+   * @note Should only be called by the Event Thread.
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Update Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by Update thread when it is ready to run the update.
+   *
+   * @param[in] notifyEvent Whether the event thread should be woken up.
+   * @param[in] runUpdate Whether to run another update. If false, then the update-thread will attempt to sleep.
+   * @param[out] lastFrameDeltaSeconds The delta, in seconds (with float precision), between the last two renders.
+   * @param[out] lastSyncTimeMilliseconds The time, in milliseconds, of the last Sync.
+   * @param[out] nextSyncTimeMilliseconds The estimated time, in milliseconds, at the next Sync.
+   * @return true if updating should continue, false if the update-thread should quit.
+   *
+   * @note Should only be called by the Update thread.
+   */
+  bool UpdateReady( bool notifyEvent, bool runUpdate, float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Render Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by the Render thread when it is ready to render.
+   *
+   * @param[in] request Pointer to set if there are any requests. This does not need to be freed by the caller.
+   *
+   * @note Should only be called by the Render thread.
+   * @note If there is a request, then the Render thread should NOT perform a Render and only process the request
+   */
+  bool RenderReady( RenderRequest*& request );
+
+  /**
+   * Called by the Render thread to inform the synchronization class that the surface has been replaced.
+   *
+   * @note Should only be called by the Render thread.
+   */
+  void RenderInformSurfaceReplaced();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the V-Sync Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by the VSync notifier thread so it can sleep if Update/Render threads are sleeping/paused
+   *
+   * @param[in] validSync True if the sync was valid (@see VSyncMonitor::DoSync)
+   * @param[in] frameNumber The current frame number
+   * @param[in] seconds The current time
+   * @param[in] microseconds The current time
+   * @param[out] numberOfVSyncsPerRender The number of frames per render.
+   * @return true if VSync monitoring/notifications should continue.
+   *
+   * @note Should only be called by the VSync thread.
+   * @note The first call to this method should be BEFORE the actual VSync so a thread-sync point can be established (and startup time is not delayed).
+   */
+  bool VSyncReady( bool validSync, unsigned int frameNumber, unsigned int seconds, unsigned int microseconds, unsigned int& numberOfVSyncsPerRender );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // POST RENDERING
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //// Called by the Event Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderComplete()
+   */
+  void PostRenderComplete();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //// Called by the Render Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
+   */
+  void PostRenderStarted();
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
+   */
+  void PostRenderWaitForCompletion();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by ALL Threads
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Helper to add a performance marker to the performance server (if it's active)
+   * @param type performance marker type
+   */
+  void AddPerformanceMarker( PerformanceInterface::MarkerType type );
+
+private:
+
+  // Undefined copy constructor.
+  ThreadSynchronization( const ThreadSynchronization& );
+
+  // Undefined assignment operator.
+  ThreadSynchronization& operator=( const ThreadSynchronization& );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by ALL Threads
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by the update, render & v-sync thread when they up and running.
+   * This will lock the mutex in mEventThreadWaitCondition.
+   */
+  inline void NotifyThreadInitialised();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by Update Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by the update-thread when the state is State::INITIALISING.
+   * Calls methods that lock and locks itself so should NOT be called while a scoped-lock is held.
+   */
+  void UpdateInitialising();
+
+  /**
+   * Called by the update thread to attempt to sleep.
+   * @param[in] runUpdate Whether to run another update. If false, then the update-thread will attempt to sleep.
+   */
+  void UpdateTryToSleep( bool runUpdate );
+
+  /**
+   * Called by the update thread to wait while the render-surface is being replaced.
+   * Calls methods that lock and locks itself so should NOT be called while a scoped-lock is held.
+   */
+  void UpdateWaitIfReplacingSurface();
+
+  /**
+   * Called by the update thread to check if we're just resuming.
+   * This will lock the mutex in mUpdateThreadWaitCondition.
+   */
+  inline bool IsUpdateThreadResuming();
+
+  /**
+   * Called by the update thread to check if the update thread should be running.
+   * This will lock the mutex in mUpdateThreadWaitCondition.
+   *
+   * @return True if we're stopping, false otherwise.
+   */
+  inline bool IsUpdateThreadStopping();
+
+  /**
+   * Called by the update thread to check if we've filled all update buffers.
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   *
+   * @return True if all update buffers are full.
+   */
+  inline bool MaximumUpdateAheadOfRenderReached();
+
+  /**
+   * Called by the update thread when we are about to stop.
+   * This will call other functions which lock various conditional wait mutexes.
+   */
+  inline void StopAllThreads();
+
+  /**
+   * Runs the V-Sync Thread.
+   * This will lock the mutex in mVSyncThreadWaitCondition.
+   */
+  inline void RunVSyncThread();
+
+  /**
+   * Pauses the V-Sync Thread.
+   * This will lock the mutex in mVSyncThreadWaitCondition.
+   */
+  inline void PauseVSyncThread();
+
+  /**
+   * Stops the V-Sync Thread.
+   * This will lock the mutex in mVSyncThreadWaitCondition.
+   */
+  inline void StopVSyncThread();
+
+  /**
+   * Stops the Render Thread.
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   */
+  inline void StopRenderThread();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by V-Sync Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Checks if the V-Sync thread should be running.
+   * This will lock the mutex in mVSyncThreadWaitCondition.
+   *
+   * @return true if running, false otherwise.
+   */
+  inline bool IsVSyncThreadRunning();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by Render Thread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Checks if the Render thread should be running.
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   *
+   * @return true if running, false otherwise.
+   */
+  inline bool IsRenderThreadRunning();
+
+  /**
+   * Checks if the render thread should be replacing the surface
+   * This will lock the mutex in mRenderThreadWaitCondition.
+   *
+   * @return true if the render thread should be replacing the surface, false otherwise.
+   */
+  inline bool IsRenderThreadReplacingSurface();
+
+private:
+
+  struct State
+  {
+    enum Type
+    {
+      STOPPED,
+      INITIALISING,
+      RUNNING,
+      PAUSED,
+      SLEEPING,
+      REPLACING_SURFACE
+    };
+  };
+
+  FrameTime mFrameTime;                               ///< Frame timer predicts next vsync time
+  TriggerEventInterface& mNotificationTrigger;        ///< Reference to notification event trigger
+  PerformanceInterface* mPerformanceInterface;        ///< The performance logging interface
+  ReplaceSurfaceRequest mReplaceSurfaceRequest;       ///< Holder for a replace surface request
+
+  ConditionalWait mUpdateThreadWaitCondition;         ///< The wait condition for the update-thread.
+  ConditionalWait mRenderThreadWaitCondition;         ///< The wait condition for the render-thread.
+  ConditionalWait mVSyncThreadWaitCondition;          ///< The wait condition for the v-sync-thread.
+  ConditionalWait mEventThreadWaitCondition;          ///< The wait condition for the event-thread.
+
+  const int mMaximumUpdateCount;                      ///< How many frames may be prepared, ahead of the rendering.
+  unsigned int mNumberOfVSyncsPerRender;              ///< How many frames for each update/render cycle.
+
+  unsigned int mTryToSleepCount;                      ///< Count to ensure we don't go to sleep too early
+
+  volatile State::Type mState;                        ///< The current state of synchronisation (set & read by both the event & update threads).
+
+  volatile int mVSyncAheadOfUpdate;                   ///< The number of frames vsync is ahead of update (set & read by both the v-sync & update threads).
+  volatile int mUpdateAheadOfRender;                  ///< The number of frames update is ahead of render (set & read by both the update & render threads).
+  volatile int mNumberOfThreadsStarted;               ///< The number of threads that are initialised and running (set by update, v-sync & render threads, read by event-thread).
+
+  //
+  // NOTE: cannot use booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
+  //
+
+  volatile unsigned int mUpdateThreadResuming;        ///< Whether the update-thread is resuming.
+
+  volatile unsigned int mVSyncThreadRunning;          ///< Whether the V-Sync thread is running (set by the update-thread, read by v-sync-thread).
+  volatile unsigned int mVSyncThreadStop;             ///< Whether the V-Sync thread should be stopped (set by the update-thread, read by the v-sync-thread).
+
+  volatile unsigned int mRenderThreadStop;            ///< Whether the render-thread should be stopped (set by the update-thread, read by the render-thread).
+  volatile unsigned int mRenderThreadReplacingSurface;///< Whether the render-thread should replace the surface (set by the event & render threads, read by the render-thread).
+
+  volatile unsigned int mRenderThreadPostRendering;   ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
+
+  volatile unsigned int mEventThreadSurfaceReplaced;  ///< Checked by the event-thread & set by the render-thread when the surface has been replaced (set by the event & render threads, read by the event-thread).
+
+  unsigned int mVSyncThreadInitialised;               ///< Whether the V-Sync thread has been initialised (only used by v-sync-thread).
+  unsigned int mRenderThreadInitialised;              ///< Whether the render-thread has been initialised (only used by the render-thread).
+  unsigned int mRenderThreadSurfaceReplaced;          ///< Whether the render-thread has replaced the surface (only used by render-thread).
+}; // class ThreadSynchronization
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_THREAD_SYNCHRONIZATION_H__
diff --git a/adaptors/base/update-thread.cpp b/adaptors/base/update-thread.cpp
new file mode 100644 (file)
index 0000000..ce80037
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "update-thread.h"
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/thread-synchronization.h>
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* DALI_TEMP_UPDATE_FPS_FILE( "/tmp/dalifps.txt" );
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gUpdateLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_UPDATE_THREAD");
+#endif
+} // unnamed namespace
+
+UpdateThread::UpdateThread( ThreadSynchronization& sync,
+                            AdaptorInternalServices& adaptorInterfaces,
+                            const EnvironmentOptions& environmentOptions )
+: mThreadSynchronization( sync ),
+  mCore( adaptorInterfaces.GetCore()),
+  mFpsTrackingSeconds( fabsf( environmentOptions.GetFrameRateLoggingFrequency() ) ),
+  mFrameCount( 0.0f ),
+  mElapsedTime( 0.0f ),
+  mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
+  mStatusLogCount( 0u ),
+  mThread( NULL ),
+  mEnvironmentOptions( environmentOptions )
+{
+}
+
+UpdateThread::~UpdateThread()
+{
+  if( mFpsTrackingSeconds > 0.f )
+  {
+    OutputFPSRecord();
+  }
+  Stop();
+}
+
+void UpdateThread::Start()
+{
+  DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Start()\n");
+  if ( !mThread )
+  {
+    // Create and run the update-thread
+    mThread =  new pthread_t();
+    int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
+    DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in UpdateThread" );
+  }
+}
+
+void UpdateThread::Stop()
+{
+  DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Stop()\n");
+  if( mThread )
+  {
+    // wait for the thread to finish
+    pthread_join(*mThread, NULL);
+
+    delete mThread;
+    mThread = NULL;
+  }
+}
+
+bool UpdateThread::Run()
+{
+  DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run()\n");
+
+  // Install a function for logging
+  mEnvironmentOptions.InstallLogFunction();
+
+  Integration::UpdateStatus status;
+  bool runUpdate = true;
+  float lastFrameDelta( 0.0f );
+  unsigned int lastSyncTime( 0 );
+  unsigned int nextSyncTime( 0 );
+
+  // Update loop, we stay inside here while the update-thread is running
+  // We also get the last delta and the predict when this update will be rendered
+  while ( mThreadSynchronization.UpdateReady( status.NeedsNotification(), runUpdate, lastFrameDelta, lastSyncTime, nextSyncTime ) )
+  {
+    DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 1 - UpdateReady(delta:%f, lastSync:%u, nextSync:%u)\n", lastFrameDelta, lastSyncTime, nextSyncTime);
+
+    DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 2 - Core.Update()\n");
+
+    mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_START );
+    mCore.Update( lastFrameDelta, lastSyncTime, nextSyncTime, status );
+    mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::UPDATE_END );
+
+    if( mFpsTrackingSeconds > 0.f )
+    {
+      FPSTracking(status.SecondsFromLastFrame());
+    }
+
+    unsigned int keepUpdatingStatus = status.KeepUpdating();
+
+    // Optional logging of update/render status
+    if ( mStatusLogInterval )
+    {
+      UpdateStatusLogging( keepUpdatingStatus );
+    }
+
+    //  2 things can keep update running.
+    // - The status of the last update
+    // - The status of the last render
+    runUpdate = (Integration::KeepUpdating::NOT_REQUESTED != keepUpdatingStatus);
+
+    DALI_LOG_INFO( gUpdateLogFilter, Debug::Verbose, "UpdateThread::Run. 3 - runUpdate(%d)\n", runUpdate );
+
+    // Reset time variables
+    lastFrameDelta = 0.0f;
+    lastSyncTime = 0;
+    nextSyncTime = 0;
+  }
+
+  // Uninstall the logging function
+  mEnvironmentOptions.UnInstallLogFunction();
+
+  return true;
+}
+
+void UpdateThread::FPSTracking( float secondsFromLastFrame )
+{
+  if ( mElapsedTime < mFpsTrackingSeconds )
+  {
+    mElapsedTime += secondsFromLastFrame;
+    mFrameCount += 1.f;
+  }
+  else
+  {
+    OutputFPSRecord();
+    mFrameCount = 0.f;
+    mElapsedTime = 0.f;
+  }
+}
+
+void UpdateThread::OutputFPSRecord()
+{
+  float fps = mFrameCount / mElapsedTime;
+  DALI_LOG_FPS("Frame count %.0f, elapsed time %.1fs, FPS: %.2f\n", mFrameCount, mElapsedTime, fps );
+
+  // Dumps out the frame rate.
+  FILE* outfile = fopen( DALI_TEMP_UPDATE_FPS_FILE, "w" );
+  if( outfile )
+  {
+    char fpsString[10];
+    snprintf(fpsString,sizeof(fpsString),"%.2f \n", fps );
+    fputs( fpsString, outfile ); // ignore the error on purpose
+    fclose( outfile );
+  }
+}
+
+void UpdateThread::UpdateStatusLogging( unsigned int keepUpdatingStatus )
+{
+  DALI_ASSERT_ALWAYS( mStatusLogInterval );
+
+  std::string oss;
+
+  if ( !(++mStatusLogCount % mStatusLogInterval) )
+  {
+    oss = "UpdateStatusLogging keepUpdating: ";
+    oss += (keepUpdatingStatus ? "true":"false");
+
+    if ( keepUpdatingStatus )
+    {
+      oss += " because: ";
+    }
+
+    if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
+    {
+      oss += "<Stage::KeepRendering() used> ";
+    }
+
+    if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
+    {
+      oss  +=  "<Animations running> ";
+    }
+
+    if ( keepUpdatingStatus & Integration::KeepUpdating::LOADING_RESOURCES )
+    {
+      oss  +=  "<Resources loading> ";
+    }
+
+    if ( keepUpdatingStatus & Integration::KeepUpdating::MONITORING_PERFORMANCE )
+    {
+      oss += "<Monitoring performance> ";
+    }
+
+    if ( keepUpdatingStatus & Integration::KeepUpdating::RENDER_TASK_SYNC )
+    {
+      oss += "<Render task waiting for completion> ";
+    }
+
+    DALI_LOG_UPDATE_STATUS( "%s\n", oss.c_str());
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/update-thread.h b/adaptors/base/update-thread.h
new file mode 100644 (file)
index 0000000..2043277
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __DALI_INTERNAL_UPDATE_THREAD_H__
+#define __DALI_INTERNAL_UPDATE_THREAD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class ThreadSynchronization;
+class AdaptorInternalServices;
+class EnvironmentOptions;
+
+/**
+ * The update-thread is responsible for calling Core::Update(), and
+ * for triggering the render-thread after each update.
+ */
+class UpdateThread
+{
+public:
+
+  /**
+   * Create the update-thread; this will not do anything until Start() is called.
+   * @param[in] sync An object used to synchronize update & render threads.
+   * @param[in] adaptorInterfaces base adaptor interface
+   * @param[in] environmentOptions environment options
+   */
+  UpdateThread(ThreadSynchronization& sync,
+               AdaptorInternalServices& adaptorInterfaces,
+               const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non-virtual destructor; UpdateThread is not suitable as a base class.
+   */
+  ~UpdateThread();
+
+  /**
+   * Starts the update-thread
+   */
+  void Start();
+
+  /**
+   * Stops the update-thread
+   */
+  void Stop();
+
+private:
+
+  /**
+   * This method is used by the update-thread for calling Core::Update().
+   * @return true, if the thread finishes properly.
+   */
+  bool Run();
+
+  /**
+   * When DALI_FPS_TRACKING is enabled, this method calculates the frame rates for the specified time period
+   */
+  void FPSTracking(float secondsFromLastFrame);
+
+  /**
+   * Output the FPS information
+   * when the FSP tracking is enabled,
+   * it is called when the specified tracking period is elapsed or in the destructor when the process finished beforehand
+   */
+  void OutputFPSRecord();
+
+  /**
+   * Optionally output the update thread status.
+   * @param[in] keepUpdatingStatus Whether the update-thread requested further updates.
+   */
+  void UpdateStatusLogging( unsigned int keepUpdatingStatus );
+
+  /**
+   * Helper for the thread calling the entry function
+   * @param[in] This A pointer to the current UpdateThread object
+   */
+  static inline void* InternalThreadEntryFunc( void* This )
+  {
+    ( static_cast<UpdateThread*>( This ) )->Run();
+    return NULL;
+  }
+
+private: // Data
+
+  ThreadSynchronization&              mThreadSynchronization; ///< Used to synchronize all the threads
+
+  Dali::Integration::Core&            mCore;                ///< Dali core reference
+
+  float                               mFpsTrackingSeconds;  ///< fps tracking time length in seconds
+  float                               mFrameCount;          ///< how many frames occurred during tracking period
+  float                               mElapsedTime;         ///< time elapsed from previous fps tracking output
+
+  unsigned int                        mStatusLogInterval;   ///< Interval in frames between status debug prints
+  unsigned int                        mStatusLogCount;      ///< Used to count frames between status debug prints
+
+  pthread_t*                          mThread;              ///< The actual update-thread.
+  const EnvironmentOptions&           mEnvironmentOptions;  ///< environment options
+}; // class UpdateThread
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_UPDATE_THREAD_H__
diff --git a/adaptors/base/vsync-notifier.cpp b/adaptors/base/vsync-notifier.cpp
new file mode 100644 (file)
index 0000000..0bedb62
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "vsync-notifier.h"
+
+// EXTERNAL INCLUDES
+#include <unistd.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/platform-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/thread-synchronization.h>
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
+const unsigned int TIME_PER_FRAME_IN_MICROSECONDS( 16667u );
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gSyncLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_VSYNC_NOTIFIER");
+#endif
+
+} // unnamed namespace
+
+VSyncNotifier::VSyncNotifier( ThreadSynchronization& sync,
+                              AdaptorInternalServices& adaptorInterfaces,
+                              const EnvironmentOptions& environmentOptions )
+: mThreadSynchronization( sync ),
+  mCore( adaptorInterfaces.GetCore() ),
+  mPlatformAbstraction( adaptorInterfaces.GetPlatformAbstractionInterface() ),
+  mVSyncMonitor( adaptorInterfaces.GetVSyncMonitorInterface() ),
+  mThread( NULL ),
+  mEnvironmentOptions( environmentOptions ),
+  mNumberOfVSyncsPerRender(1)
+{
+}
+
+VSyncNotifier::~VSyncNotifier()
+{
+  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
+
+  Stop();
+}
+
+void VSyncNotifier::Start()
+{
+  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
+
+  if ( !mThread )
+  {
+    mVSyncMonitor->Initialize();
+
+    mThread = new pthread_t();
+    int error = pthread_create( mThread, NULL, InternalThreadEntryFunc, this );
+    DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() in VSyncNotifier" );
+  }
+}
+
+void VSyncNotifier::Stop()
+{
+  DALI_LOG_INFO( gSyncLogFilter, Debug::General, "%s\n", __func__ );
+
+  if( mThread )
+  {
+    // wait for the thread to finish
+    pthread_join(*mThread, NULL);
+
+    delete mThread;
+    mThread = NULL;
+  }
+
+  mVSyncMonitor->Terminate();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// The following is executed inside the notifier thread !!!
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void VSyncNotifier::Run()
+{
+  // install a function for logging
+  mEnvironmentOptions.InstallLogFunction();
+
+  unsigned int frameNumber( 0u );             // frameCount, updated when the thread is paused
+  unsigned int currentSequenceNumber( 0u );   // platform specific vsync sequence number (increments with each vsync)
+  unsigned int currentSeconds( 0u );          // timestamp at latest sync
+  unsigned int currentMicroseconds( 0u );     // timestamp at latest sync
+  unsigned int seconds( 0u );
+  unsigned int microseconds( 0u );
+
+  bool validSync( true );
+  while( mThreadSynchronization.VSyncReady( validSync, frameNumber++, currentSeconds, currentMicroseconds, mNumberOfVSyncsPerRender ) )
+  {
+    DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 1 SyncWithUpdateAndRender(frame#:%d, current Sec:%u current uSec:%u)\n", frameNumber-1, currentSeconds, currentMicroseconds);
+
+    // Hardware VSyncs available?
+    if( mVSyncMonitor->UseHardware() )
+    {
+      DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start hardware sync (%d frames) \n", mNumberOfVSyncsPerRender);
+
+      for( unsigned int i=0; i<mNumberOfVSyncsPerRender; ++i )
+      {
+        // Yes..wait for N hardware VSync ticks
+        validSync = mVSyncMonitor->DoSync( currentSequenceNumber, currentSeconds, currentMicroseconds );
+      }
+    }
+    else
+    {
+      // No..use software timer
+      mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds );
+
+      unsigned int timeDelta( MICROSECONDS_PER_SECOND * (seconds - currentSeconds) );
+      if( microseconds < currentMicroseconds)
+      {
+        timeDelta += (microseconds + MICROSECONDS_PER_SECOND) - currentMicroseconds;
+      }
+      else
+      {
+        timeDelta += microseconds - currentMicroseconds;
+      }
+
+      currentSeconds = seconds;
+      currentMicroseconds = microseconds;
+
+      unsigned int sleepTimeInMicroseconds = 0;
+
+      if( timeDelta < TIME_PER_FRAME_IN_MICROSECONDS )
+      {
+        sleepTimeInMicroseconds = TIME_PER_FRAME_IN_MICROSECONDS - timeDelta;
+      }
+      sleepTimeInMicroseconds += mNumberOfVSyncsPerRender * TIME_PER_FRAME_IN_MICROSECONDS;
+
+      DALI_LOG_INFO( gSyncLogFilter, Debug::General, "VSyncNotifier::Run. 2 Start software sync (%d frames, %u microseconds) \n", mNumberOfVSyncsPerRender, sleepTimeInMicroseconds);
+
+      timespec sleepTime;
+      sleepTime.tv_sec = 0;
+      sleepTime.tv_nsec = sleepTimeInMicroseconds * 1000;
+      nanosleep( &sleepTime, NULL );
+    }
+    mThreadSynchronization.AddPerformanceMarker( PerformanceInterface::VSYNC );
+  }
+
+  // uninstall a function for logging
+  mEnvironmentOptions.UnInstallLogFunction();
+
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/base/vsync-notifier.h b/adaptors/base/vsync-notifier.h
new file mode 100644 (file)
index 0000000..fd6bdc3
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef __DALI_INTERNAL_VSYNC_NOTIFIER_H__
+#define __DALI_INTERNAL_VSYNC_NOTIFIER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+class Core;
+class PlatformAbstraction;
+
+} // namespace Integration
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class VSyncMonitorInterface;
+class ThreadSynchronization;
+class EnvironmentOptions;
+class AdaptorInternalServices;
+
+/**
+ * Implements a simple class that either monitors vertical blanks from libdrm, or manages
+ * a software timer to handle syncing.
+ */
+class VSyncNotifier
+{
+public:
+
+  /**
+   * Create the vsync notification thread; this will not start to monitor vsync and
+   * send notifications until Start() is called.
+   * @param[in] sync         An object used to synchronize update, render and vsync threads.
+   * @param[in] adaptorInterfaces base adaptor interface
+   * @param[in] environmentOptions environment options
+   */
+  VSyncNotifier( ThreadSynchronization& sync,
+                 AdaptorInternalServices& adaptorInterfaces,
+                 const EnvironmentOptions& environmentOptions);
+
+  /**
+   * Non-virtual destructor; VSyncNotifier is not suitable as a base class.
+   */
+  ~VSyncNotifier();
+
+  /**
+   * Starts the thread
+   */
+  void Start();
+
+  /**
+   * Stops the thread
+   */
+  void Stop();
+
+private:
+
+  /**
+   * The main thread loop. The system thread will be destroyed on
+   * exit from this function.
+   */
+  void Run();
+
+  /**
+   * Helper for the thread calling the entry function
+   * @param[in] This A pointer to the current VSyncNotifier object
+   */
+  static inline void* InternalThreadEntryFunc( void* This )
+  {
+    ( static_cast<VSyncNotifier*>( This ) )->Run();
+    return NULL;
+  }
+
+private:
+
+  ThreadSynchronization&              mThreadSynchronization;   ///< Used to synchronize all the threads
+  Dali::Integration::Core&            mCore;                    ///< Dali core reference
+  Integration::PlatformAbstraction&   mPlatformAbstraction;     ///< The platform abstraction for retrieving the current time etc.
+  VSyncMonitorInterface*              mVSyncMonitor;            ///< VSyncMonitor interface
+  pthread_t*                          mThread;                  ///< The actual thread.
+  const EnvironmentOptions&           mEnvironmentOptions;      ///< Environment options
+  unsigned int                        mNumberOfVSyncsPerRender; ///< How many frames for each update/render cycle.
+
+}; // class VSyncNotifier
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_VSYNC_NOTIFIER_H__
diff --git a/adaptors/common/abort-handler.cpp b/adaptors/common/abort-handler.cpp
new file mode 100644 (file)
index 0000000..ed4d09e
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "abort-handler.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+AbortHandler* AbortHandler::gInstance(NULL);
+
+AbortHandler::AbortHandler( CallbackBase* callback )
+: mSignalMask( 0 ),
+  mCallback( callback )
+{
+  DALI_ASSERT_ALWAYS( gInstance == NULL && "Only one instance of abort handler allowed" );
+  gInstance = this;
+
+  memset( mSignalOldHandlers, 0, sizeof(SignalHandlerFuncPtr) * (_NSIG-1));
+}
+
+AbortHandler::~AbortHandler()
+{
+  delete mCallback;
+
+  int signum;
+  for ( signum = 1; signum < _NSIG; signum++ )
+  {
+    if ( mSignalMask & (1 << (signum-1) ) )
+    {
+      // set signals back to default handling
+      signal( signum, mSignalOldHandlers[signum-1] );
+    }
+  }
+  gInstance = NULL;
+}
+
+bool AbortHandler::AbortOnSignal( int signum )
+{
+  bool status = false;
+
+  if ( signum < _NSIG )
+  {
+    SignalHandlerFuncPtr signalHandlerPrevious = signal( signum, &AbortHandler::SignalHandler );
+
+    if ( SIG_ERR != signalHandlerPrevious )
+    {
+      mSignalOldHandlers[signum-1] = signalHandlerPrevious;
+      mSignalMask |= ( 1 << (signum-1) );
+      status = true;
+    }
+  }
+  return status;
+}
+
+void AbortHandler::SignalHandler( int signum )
+{
+  if( gInstance )
+  {
+    if( gInstance->mCallback )
+    {
+      CallbackBase::Execute( *gInstance->mCallback );
+    }
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/abort-handler.h b/adaptors/common/abort-handler.h
new file mode 100644 (file)
index 0000000..df2b619
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H__
+#define __DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <signal.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include "application.h"
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Class to listen to system signals and trigger an abort callback
+ * when they occur.
+ *
+ * This class maintains a process wide singleton, as the signal(2) system
+ * call is process specific, not thread specific.
+ *
+ * Currently, this precludes having multiple DALi instances in the same process.
+ */
+class AbortHandler
+{
+public:
+  /**
+   * Constructor
+   * @param[in] callback The function to call when abort signals occur
+   * @note The ownership of callback is passed onto this class.
+   */
+  AbortHandler( CallbackBase* callback );
+
+  /**
+   * Destructor
+   */
+  ~AbortHandler();
+
+  /**
+   * Add a signal you want to be handled by this abort handler.
+   * @param[in] signum The signal number (from signum.h)
+   * @return true if the signal handler was installed ok
+   */
+  bool AbortOnSignal( int signum );
+
+private:
+  /**
+   * Signal handler - Called when signal is received.
+   * Stops the application.
+   */
+  static void SignalHandler( int signum );
+
+  /**
+   * Default constructor - undefined
+   */
+  AbortHandler();
+
+  /**
+   * Copy constructor - undefined
+   */
+  AbortHandler(const AbortHandler& rhs);
+
+  /**
+   * Assignment operator - undefined
+   */
+  AbortHandler& operator=(const AbortHandler& rhs);
+
+private:
+  typedef void (*SignalHandlerFuncPtr )( int );
+
+  // _NSIG comes from the signal.h linux system header, defining the number of signals.
+  SignalHandlerFuncPtr        mSignalOldHandlers[_NSIG-1];
+  unsigned long long          mSignalMask;
+
+  CallbackBase*               mCallback;
+
+  static AbortHandler*        gInstance;
+};
+
+} // Namespace Adaptor
+} // Namespace Internal
+} // Namespace Dali
+
+#endif //  __DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H__
diff --git a/adaptors/common/accessibility-adaptor-impl.h b/adaptors/common/accessibility-adaptor-impl.h
new file mode 100644 (file)
index 0000000..c529a80
--- /dev/null
@@ -0,0 +1,301 @@
+#ifndef __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
+#define __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/integration-api/events/touch-event-combiner.h>
+
+// INTERNAL INCLUDES
+#include <accessibility-adaptor.h>
+#include <accessibility-action-handler.h>
+#include <accessibility-gesture-handler.h>
+#include <indicator-impl.h>
+#include <accessibility-gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This class detects to accessibility action
+ */
+class AccessibilityAdaptor : public Dali::BaseObject
+{
+public:
+
+  // Creation
+
+  /**
+   * Constructor.
+   */
+  AccessibilityAdaptor();
+
+  /**
+   * Get an instance of the AccessibilityAdaptor.
+   * @return The instance of the AccessibilityAdaptor.
+   */
+  static Dali::AccessibilityAdaptor Get();
+
+  // Public API
+
+  /**
+   * Turn on accessibility action
+   * This method should be called by vconf callback
+   */
+  void EnableAccessibility();
+
+  /**
+   * Turn off accessibility action
+   * This method should be called by vconf callback
+   */
+  void DisableAccessibility();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::IsEnabled()
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::GetReadPosition() const
+   */
+  Vector2 GetReadPosition() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetActionHandler()
+   */
+  void SetActionHandler(AccessibilityActionHandler& handler);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetGestureHandler()
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  /**
+   * Set the Indicator
+   */
+  void SetIndicator(Indicator* indicator);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent()
+   */
+  bool HandleActionNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent()
+   */
+  bool HandleActionPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent()
+   */
+  bool HandleActionActivateEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent()
+   */
+  bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent()
+   */
+  bool HandleActionReadNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent()
+   */
+  bool HandleActionReadPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent()
+   */
+  bool HandleActionUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent()
+   */
+  bool HandleActionDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionClearFocusEvent()
+   */
+  bool HandleActionClearFocusEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollEvent()
+   */
+  bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionTouchEvent()
+   */
+  bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionBackEvent()
+   */
+  bool HandleActionBackEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionEnableEvent()
+   */
+  void HandleActionEnableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDisableEvent()
+   */
+  void HandleActionDisableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollUpEvent()
+   */
+  bool HandleActionScrollUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollDownEvent()
+   */
+  bool HandleActionScrollDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageLeftEvent()
+   */
+  bool HandleActionPageLeftEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageRightEvent()
+   */
+  bool HandleActionPageRightEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageUpEvent()
+   */
+  bool HandleActionPageUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageDownEvent()
+   */
+  bool HandleActionPageDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+   */
+  bool HandleActionMoveToFirstEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToLastEvent()
+   */
+  bool HandleActionMoveToLastEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromTopEvent()
+   */
+  bool HandleActionReadFromTopEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromNextEvent()
+   */
+  bool HandleActionReadFromNextEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionZoomEvent()
+   */
+  bool HandleActionZoomEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+   */
+  bool HandleActionReadIndicatorInformationEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+   */
+  bool HandleActionReadPauseResumeEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionStartStopEvent()
+   */
+  bool HandleActionStartStopEvent();
+
+private:
+
+  // Destruction
+
+  /**
+   * Destructor.
+   */
+  virtual ~AccessibilityAdaptor();
+
+  // Undefined
+  AccessibilityAdaptor( const AccessibilityAdaptor& );
+  AccessibilityAdaptor& operator=( AccessibilityAdaptor& );
+
+private:
+
+  Dali::Integration::TouchEventCombiner mCombiner; ///< Combines multi-touch events.
+
+  bool mIsEnabled; ///< enable/disable the accessibility action
+  Vector2 mReadPosition; ///< ActionRead position
+
+  AccessibilityActionHandler* mActionHandler; ///< The pointer of accessibility action handler
+
+  AccessibilityGestureDetectorPtr mAccessibilityGestureDetector; ///< The accessibility gesture detector
+
+  Indicator* mIndicator; ///< The indicator
+  bool mIndicatorFocused; ///< Whether the Indicator is focused
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+  inline static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    const BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
diff --git a/adaptors/common/accessibility-gesture-detector.cpp b/adaptors/common/accessibility-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..173eabe
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "accessibility-gesture-detector.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/events/gesture-requests.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+AccessibilityGestureDetector::AccessibilityGestureDetector()
+: PanGestureDetectorBase(Vector2::ZERO, Integration::PanGestureRequest(), NULL),
+  mGestureHandler(NULL),
+  mPanning(false)
+{
+}
+
+AccessibilityGestureDetector::~AccessibilityGestureDetector()
+{
+}
+
+void AccessibilityGestureDetector::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  mGestureHandler = &handler;
+}
+
+void AccessibilityGestureDetector::EmitPan(const Integration::PanGestureEvent gesture)
+{
+  if( mGestureHandler )
+  {
+    if(gesture.state == Gesture::Started)
+    {
+      mPanning = true;
+    }
+
+    if( mPanning )
+    {
+      mGestureHandler->HandlePanGesture(gesture);
+
+      if( (gesture.state == Gesture::Finished) ||
+          (gesture.state == Gesture::Cancelled) )
+      {
+        mPanning = false;
+      }
+    }
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/accessibility-gesture-detector.h b/adaptors/common/accessibility-gesture-detector.h
new file mode 100644 (file)
index 0000000..91b3b7e
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef __DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <events/pan-gesture-detector-base.h>
+#include <adaptor-impl.h>
+#include <accessibility-gesture-handler.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+struct TouchEvent;
+struct PanGestureRequest;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Detects an accessibility pan gesture and sends it to the gesture handler.
+ */
+class AccessibilityGestureDetector : public PanGestureDetectorBase
+{
+public:
+
+  /**
+   * Constructor
+   */
+  AccessibilityGestureDetector();
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~AccessibilityGestureDetector();
+
+  /**
+   * Set the handler to handle accessibility gestures.
+   * @param[in] handler The Accessibility gesture handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+private:
+
+  /**
+   * Emits the pan gesture event to the gesture handler.
+   * @param[in] gesture The pan gesture event.
+   */
+  virtual void EmitPan(const Integration::PanGestureEvent gesture);
+
+private:
+
+  AccessibilityGestureHandler* mGestureHandler; ///< The pointer of accessibility gesture handler
+  bool mPanning;    ///< Keep track of panning state, when panning is occuring, this is true.
+};
+
+typedef IntrusivePtr<AccessibilityGestureDetector> AccessibilityGestureDetectorPtr;
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/adaptor-impl.cpp b/adaptors/common/adaptor-impl.cpp
new file mode 100644 (file)
index 0000000..a5e1330
--- /dev/null
@@ -0,0 +1,851 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "adaptor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/context-notifier.h>
+#include <dali/integration-api/profiling.h>
+#include <dali/integration-api/input-options.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <base/thread-controller.h>
+#if defined(NETWORK_ENABLED)
+#  include <base/performance-logging/performance-interface-factory.h>
+#endif
+#include <base/lifecycle-observer.h>
+
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+#include <callback-manager.h>
+#include <render-surface.h>
+#include <tts-player-impl.h>
+#include <accessibility-adaptor-impl.h>
+#include <events/gesture-manager.h>
+#include <events/event-handler.h>
+#include <gl/gl-proxy-implementation.h>
+#include <gl/gl-implementation.h>
+#include <gl/egl-sync-implementation.h>
+#include <gl/egl-image-extensions.h>
+#include <gl/egl-factory.h>
+#include <imf-manager-impl.h>
+#include <clipboard-impl.h>
+#include <vsync-monitor.h>
+#include <object-profiler.h>
+#include <base/display-connection.h>
+#include <window-impl.h>
+
+#include <tizen-logging.h>
+
+using Dali::TextAbstraction::FontClient;
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+__thread Adaptor* gThreadLocalAdaptor = NULL; // raw thread specific pointer to allow Adaptor::Get
+} // unnamed namespace
+
+Dali::Adaptor* Adaptor::New( Any nativeWindow, RenderSurface *surface, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Dali::Adaptor* adaptor = new Dali::Adaptor;
+  Adaptor* impl = new Adaptor( nativeWindow, *adaptor, surface, environmentOptions );
+  adaptor->mImpl = impl;
+
+  impl->Initialize(configuration);
+
+  return adaptor;
+}
+
+Dali::Adaptor* Adaptor::New( Dali::Window window, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Any winId = window.GetNativeHandle();
+
+  Window& windowImpl = Dali::GetImplementation(window);
+  Dali::Adaptor* adaptor = New( winId, windowImpl.GetSurface(), configuration, environmentOptions );
+  windowImpl.SetAdaptor(*adaptor);
+  return adaptor;
+}
+
+void Adaptor::Initialize( Dali::Configuration::ContextLoss configuration )
+{
+  // all threads here (event, update, and render) will send their logs to TIZEN Platform's LogMessage handler.
+  Dali::Integration::Log::LogFunction logFunction( Dali::TizenPlatform::LogMessage );
+  mEnvironmentOptions->SetLogFunction( logFunction );
+  mEnvironmentOptions->InstallLogFunction(); // install logging for main thread
+
+  mPlatformAbstraction = new TizenPlatform::TizenPlatformAbstraction;
+
+  std::string path;
+  GetDataStoragePath( path );
+  mPlatformAbstraction->SetDataStoragePath( path );
+
+  ResourcePolicy::DataRetention dataRetentionPolicy = ResourcePolicy::DALI_DISCARDS_ALL_DATA;
+  if( configuration == Dali::Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS )
+  {
+    dataRetentionPolicy = ResourcePolicy::DALI_DISCARDS_ALL_DATA;
+  }
+  // Note, Tizen does not use DALI_RETAINS_ALL_DATA, as it can reload images from
+  // files automatically.
+
+#if defined(NETWORK_ENABLED)
+  if( mEnvironmentOptions->PerformanceServerRequired() )
+  {
+    mPerformanceInterface = PerformanceInterfaceFactory::CreateInterface( *this, *mEnvironmentOptions );
+  }
+#endif
+
+  mCallbackManager = CallbackManager::New();
+
+  PositionSize size = mSurface->GetPositionSize();
+
+  mGestureManager = new GestureManager(*this, Vector2(size.width, size.height), mCallbackManager, *mEnvironmentOptions);
+
+  if( mEnvironmentOptions->GetGlesCallTime() > 0 )
+  {
+    mGLES = new GlProxyImplementation( *mEnvironmentOptions );
+  }
+  else
+  {
+    mGLES = new GlImplementation();
+  }
+
+  mEglFactory = new EglFactory();
+
+  EglSyncImplementation* eglSyncImpl = mEglFactory->GetSyncImplementation();
+
+  mCore = Integration::Core::New( *this, *mPlatformAbstraction, *mGLES, *eglSyncImpl, *mGestureManager, dataRetentionPolicy );
+
+  const unsigned int timeInterval = mEnvironmentOptions->GetObjectProfilerInterval();
+  if( 0u < timeInterval )
+  {
+    mObjectProfiler = new ObjectProfiler( timeInterval );
+  }
+
+  mNotificationTrigger = mTriggerEventFactory.CreateTriggerEvent( MakeCallback( this, &Adaptor::ProcessCoreEvents ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
+
+  mVSyncMonitor = new VSyncMonitor;
+
+  mThreadController = new ThreadController( *this, *mEnvironmentOptions );
+
+  // Should be called after Core creation
+  if( mEnvironmentOptions->GetPanGestureLoggingLevel() )
+  {
+    Integration::EnableProfiling( Dali::Integration::PROFILING_TYPE_PAN_GESTURE );
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionMode() >= 0 )
+  {
+    Integration::SetPanGesturePredictionMode(mEnvironmentOptions->GetPanGesturePredictionMode());
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionAmount() >= 0 )
+  {
+    Integration::SetPanGesturePredictionAmount(mEnvironmentOptions->GetPanGesturePredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureMaximumPredictionAmount() >= 0 )
+  {
+    Integration::SetPanGestureMaximumPredictionAmount(mEnvironmentOptions->GetPanGestureMaximumPredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureMinimumPredictionAmount() >= 0 )
+  {
+    Integration::SetPanGestureMinimumPredictionAmount(mEnvironmentOptions->GetPanGestureMinimumPredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment() >= 0 )
+  {
+    Integration::SetPanGesturePredictionAmountAdjustment(mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment());
+  }
+  if( mEnvironmentOptions->GetPanGestureSmoothingMode() >= 0 )
+  {
+    Integration::SetPanGestureSmoothingMode(mEnvironmentOptions->GetPanGestureSmoothingMode());
+  }
+  if( mEnvironmentOptions->GetPanGestureSmoothingAmount() >= 0.0f )
+  {
+    Integration::SetPanGestureSmoothingAmount(mEnvironmentOptions->GetPanGestureSmoothingAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureUseActualTimes() >= 0 )
+  {
+    Integration::SetPanGestureUseActualTimes( mEnvironmentOptions->GetPanGestureUseActualTimes() == 0 ? true : false );
+  }
+  if( mEnvironmentOptions->GetPanGestureInterpolationTimeRange() >= 0 )
+  {
+    Integration::SetPanGestureInterpolationTimeRange( mEnvironmentOptions->GetPanGestureInterpolationTimeRange() );
+  }
+  if( mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() >= 0 )
+  {
+    Integration::SetPanGestureScalarOnlyPredictionEnabled( mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() == 0 ? true : false  );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() >= 0 )
+  {
+    Integration::SetPanGestureTwoPointPredictionEnabled( mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() == 0 ? true : false  );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime() >= 0 )
+  {
+    Integration::SetPanGestureTwoPointInterpolatePastTime( mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime() );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointVelocityBias() >= 0.0f )
+  {
+    Integration::SetPanGestureTwoPointVelocityBias( mEnvironmentOptions->GetPanGestureTwoPointVelocityBias() );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias() >= 0.0f )
+  {
+    Integration::SetPanGestureTwoPointAccelerationBias( mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias() );
+  }
+  if( mEnvironmentOptions->GetPanGestureMultitapSmoothingRange() >= 0 )
+  {
+    Integration::SetPanGestureMultitapSmoothingRange( mEnvironmentOptions->GetPanGestureMultitapSmoothingRange() );
+  }
+}
+
+Adaptor::~Adaptor()
+{
+  // Ensure stop status
+  Stop();
+
+  // set to NULL first as we do not want any access to Adaptor as it is being destroyed.
+  gThreadLocalAdaptor = NULL;
+
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnDestroy();
+  }
+
+  delete mThreadController; // this will shutdown render thread, which will call Core::ContextDestroyed before exit
+  delete mVSyncMonitor;
+  delete mEventHandler;
+  delete mObjectProfiler;
+
+  delete mCore;
+  delete mEglFactory;
+  delete mGLES;
+  delete mGestureManager;
+  delete mPlatformAbstraction;
+  delete mCallbackManager;
+  delete mPerformanceInterface;
+
+  // uninstall it on this thread (main actor thread)
+  Dali::Integration::Log::UninstallLogFunction();
+
+  // Delete environment options if we own it
+  if( mEnvironmentOptionsOwned )
+  {
+    delete mEnvironmentOptions;
+  }
+}
+
+void Adaptor::Start()
+{
+  // it doesn't support restart after stop at this moment
+  // to support restarting, need more testing
+  if( READY != mState )
+  {
+    return;
+  }
+
+  // Start the callback manager
+  mCallbackManager->Start();
+
+  // create event handler
+  mEventHandler = new EventHandler( mSurface, *this, *mGestureManager, *this, mDragAndDropDetector );
+
+  if( mDeferredRotationObserver != NULL )
+  {
+    mEventHandler->SetRotationObserver(mDeferredRotationObserver);
+    mDeferredRotationObserver = NULL;
+  }
+
+  unsigned int dpiHor, dpiVer;
+  dpiHor = dpiVer = 0;
+  Dali::DisplayConnection::GetDpi(dpiHor, dpiVer);
+
+  // tell core about the DPI value
+  mCore->SetDpi(dpiHor, dpiVer);
+
+  // set the DPI value for font rendering
+  FontClient fontClient = FontClient::Get();
+  fontClient.SetDpi( dpiHor, dpiVer );
+
+  // Tell the core the size of the surface just before we start the render-thread
+  PositionSize size = mSurface->GetPositionSize();
+  mCore->SurfaceResized( size.width, size.height );
+
+  // Initialize the thread controller
+  mThreadController->Initialize();
+
+  mState = RUNNING;
+
+  ProcessCoreEvents(); // Ensure any startup messages are processed.
+
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnStart();
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::Pause
+void Adaptor::Pause()
+{
+  // Only pause the adaptor if we're actually running.
+  if( RUNNING == mState )
+  {
+    // Inform observers that we are about to be paused.
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnPause();
+    }
+
+    // Reset the event handler when adaptor paused
+    if( mEventHandler )
+    {
+      mEventHandler->Pause();
+    }
+
+    mThreadController->Pause();
+    mCore->Suspend();
+    mState = PAUSED;
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::Resume
+void Adaptor::Resume()
+{
+  // Only resume the adaptor if we are in the suspended state.
+  if( PAUSED == mState )
+  {
+    mState = RUNNING;
+
+    // Reset the event handler when adaptor resumed
+    if( mEventHandler )
+    {
+      mEventHandler->Resume();
+    }
+
+    // Inform observers that we have resumed.
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnResume();
+    }
+
+    // Resume core so it processes any requests as well
+    mCore->Resume();
+
+    // Do at end to ensure our first update/render after resumption includes the processed messages as well
+    mThreadController->Resume();
+  }
+}
+
+void Adaptor::Stop()
+{
+  if( RUNNING == mState ||
+      PAUSED  == mState ||
+      PAUSED_WHILE_HIDDEN == mState )
+  {
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnStop();
+    }
+
+    mThreadController->Stop();
+    mCore->Suspend();
+
+    // Delete the TTS player
+    for(int i =0; i < Dali::TtsPlayer::MODE_NUM; i++)
+    {
+      if(mTtsPlayers[i])
+      {
+        mTtsPlayers[i].Reset();
+      }
+    }
+
+    delete mEventHandler;
+    mEventHandler = NULL;
+
+    delete mNotificationTrigger;
+    mNotificationTrigger = NULL;
+
+    mCallbackManager->Stop();
+
+    mState = STOPPED;
+  }
+}
+
+void Adaptor::ContextLost()
+{
+  mCore->GetContextNotifier()->NotifyContextLost(); // Inform stage
+}
+
+void Adaptor::ContextRegained()
+{
+  // Inform core, so that texture resources can be reloaded
+  mCore->RecoverFromContextLoss();
+
+  mCore->GetContextNotifier()->NotifyContextRegained(); // Inform stage
+}
+
+void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  mEventHandler->FeedTouchPoint( point, timeStamp );
+}
+
+void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  mEventHandler->FeedWheelEvent( wheelEvent );
+}
+
+void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+{
+  mEventHandler->FeedKeyEvent( keyEvent );
+}
+
+bool Adaptor::MoveResize( const PositionSize& positionSize )
+{
+  PositionSize old = mSurface->GetPositionSize();
+
+  // just resize the surface. The driver should automatically resize the egl Surface (untested)
+  // EGL Spec says : EGL window surfaces need to be resized when their corresponding native window
+  // is resized. Implementations typically use hooks into the OS and native window
+  // system to perform this resizing on demand, transparently to the client.
+  mSurface->MoveResize( positionSize );
+
+  if(old.width != positionSize.width || old.height != positionSize.height)
+  {
+    SurfaceSizeChanged(positionSize);
+  }
+
+  return true;
+}
+
+void Adaptor::SurfaceResized( const PositionSize& positionSize )
+{
+  PositionSize old = mSurface->GetPositionSize();
+
+  // Called by an application, when it has resized a window outside of Dali.
+  // The EGL driver automatically detects X Window resize calls, and resizes
+  // the EGL surface for us.
+  mSurface->MoveResize( positionSize );
+
+  if(old.width != positionSize.width || old.height != positionSize.height)
+  {
+    SurfaceSizeChanged(positionSize);
+  }
+}
+
+void Adaptor::ReplaceSurface( Any nativeWindow, RenderSurface& surface )
+{
+  mNativeWindow = nativeWindow;
+  mSurface = &surface;
+
+  SurfaceSizeChanged(mSurface->GetPositionSize());
+
+  // flush the event queue to give update and render threads chance
+  // to start processing messages for new camera setup etc as soon as possible
+  ProcessCoreEvents();
+
+  // this method blocks until the render thread has completed the replace.
+  mThreadController->ReplaceSurface(mSurface);
+}
+
+RenderSurface& Adaptor::GetSurface() const
+{
+  return *mSurface;
+}
+
+void Adaptor::ReleaseSurfaceLock()
+{
+  mSurface->ReleaseLock();
+}
+
+Dali::TtsPlayer Adaptor::GetTtsPlayer(Dali::TtsPlayer::Mode mode)
+{
+  if(!mTtsPlayers[mode])
+  {
+    // Create the TTS player when it needed, because it can reduce launching time.
+    mTtsPlayers[mode] = TtsPlayer::New(mode);
+  }
+
+  return mTtsPlayers[mode];
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback )
+{
+  bool idleAdded(false);
+
+  // Only add an idle if the Adaptor is actually running
+  if( RUNNING == mState )
+  {
+    idleAdded = mCallbackManager->AddIdleCallback( callback );
+  }
+
+  return idleAdded;
+}
+
+
+Dali::Adaptor& Adaptor::Get()
+{
+  DALI_ASSERT_ALWAYS( IsAvailable() && "Adaptor not instantiated" );
+  return gThreadLocalAdaptor->mAdaptor;
+}
+
+bool Adaptor::IsAvailable()
+{
+  return gThreadLocalAdaptor != NULL;
+}
+
+void Adaptor::SceneCreated()
+{
+  mCore->SceneCreated();
+}
+
+Dali::Integration::Core& Adaptor::GetCore()
+{
+  return *mCore;
+}
+
+void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+  mThreadController->SetRenderRefreshRate( numberOfVSyncsPerRender );
+}
+
+void Adaptor::SetUseHardwareVSync( bool useHardware )
+{
+  mVSyncMonitor->SetUseHardwareVSync( useHardware );
+}
+
+EglFactory& Adaptor::GetEGLFactory() const
+{
+  DALI_ASSERT_DEBUG( mEglFactory && "EGL Factory not created" );
+  return *mEglFactory;
+}
+
+EglFactoryInterface& Adaptor::GetEGLFactoryInterface() const
+{
+  return *mEglFactory;
+}
+
+Integration::GlAbstraction& Adaptor::GetGlAbstraction() const
+{
+  DALI_ASSERT_DEBUG( mGLES && "GLImplementation not created" );
+  return *mGLES;
+}
+
+Dali::Integration::PlatformAbstraction& Adaptor::GetPlatformAbstractionInterface()
+{
+  return *mPlatformAbstraction;
+}
+
+Dali::Integration::GlAbstraction& Adaptor::GetGlesInterface()
+{
+  return *mGLES;
+}
+
+TriggerEventInterface& Adaptor::GetProcessCoreEventsTrigger()
+{
+  return *mNotificationTrigger;
+}
+
+TriggerEventFactoryInterface& Adaptor::GetTriggerEventFactoryInterface()
+{
+  return mTriggerEventFactory;
+}
+
+SocketFactoryInterface& Adaptor::GetSocketFactoryInterface()
+{
+  return mSocketFactory;
+}
+
+RenderSurface* Adaptor::GetRenderSurfaceInterface()
+{
+  return mSurface;
+}
+
+VSyncMonitorInterface* Adaptor::GetVSyncMonitorInterface()
+{
+  return mVSyncMonitor;
+}
+
+TraceInterface& Adaptor::GetKernelTraceInterface()
+{
+  return mKernelTracer;
+}
+
+TraceInterface& Adaptor::GetSystemTraceInterface()
+{
+  return mSystemTracer;
+}
+
+PerformanceInterface* Adaptor::GetPerformanceInterface()
+{
+  return mPerformanceInterface;
+}
+
+Integration::PlatformAbstraction& Adaptor::GetPlatformAbstraction() const
+{
+  DALI_ASSERT_DEBUG( mPlatformAbstraction && "PlatformAbstraction not created" );
+  return *mPlatformAbstraction;
+}
+
+void Adaptor::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
+{
+  mDragAndDropDetector = detector;
+
+  if ( mEventHandler )
+  {
+    mEventHandler->SetDragAndDropDetector( detector );
+  }
+}
+
+void Adaptor::SetRotationObserver( RotationObserver* observer )
+{
+  if( mEventHandler )
+  {
+    mEventHandler->SetRotationObserver( observer );
+  }
+  else if( mState == READY )
+  {
+    // Set once event handler exists
+    mDeferredRotationObserver = observer;
+  }
+}
+
+void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
+{
+  if(mTtsPlayers[mode])
+  {
+    mTtsPlayers[mode].Reset();
+  }
+}
+
+void Adaptor::SetMinimumPinchDistance(float distance)
+{
+  if( mGestureManager )
+  {
+    mGestureManager->SetMinimumPinchDistance(distance);
+  }
+}
+
+Any Adaptor::GetNativeWindowHandle()
+{
+  return mNativeWindow;
+}
+
+void Adaptor::AddObserver( LifeCycleObserver& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match == mObservers.end() )
+  {
+    mObservers.push_back( &observer );
+  }
+}
+
+void Adaptor::RemoveObserver( LifeCycleObserver& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match != mObservers.end() )
+  {
+    mObservers.erase( match );
+  }
+}
+
+void Adaptor::QueueCoreEvent(const Dali::Integration::Event& event)
+{
+  if( mCore )
+  {
+    mCore->QueueEvent(event);
+  }
+}
+
+void Adaptor::ProcessCoreEvents()
+{
+  if( mCore )
+  {
+    if( mPerformanceInterface )
+    {
+      mPerformanceInterface->AddMarker( PerformanceInterface::PROCESS_EVENTS_START );
+    }
+
+    mCore->ProcessEvents();
+
+    if( mPerformanceInterface )
+    {
+      mPerformanceInterface->AddMarker( PerformanceInterface::PROCESS_EVENTS_END );
+    }
+  }
+}
+
+void Adaptor::RequestUpdate()
+{
+  // When Dali applications are partially visible behind the lock-screen,
+  // the indicator must be updated (therefore allow updates in the PAUSED state)
+  if ( PAUSED  == mState ||
+       RUNNING == mState )
+  {
+    mThreadController->RequestUpdate();
+  }
+}
+
+void Adaptor::RequestProcessEventsOnIdle()
+{
+  // Only request a notification if the Adaptor is actually running
+  // and we haven't installed the idle notification
+  if( ( ! mNotificationOnIdleInstalled ) && ( RUNNING == mState ) )
+  {
+    mNotificationOnIdleInstalled = AddIdle( MakeCallback( this, &Adaptor::ProcessCoreEventsFromIdle ) );
+  }
+}
+
+void Adaptor::OnWindowShown()
+{
+  if ( PAUSED_WHILE_HIDDEN == mState )
+  {
+    // Adaptor can now be resumed
+    mState = PAUSED;
+
+    Resume();
+
+    // Force a render task
+    RequestUpdateOnce();
+  }
+}
+
+void Adaptor::OnWindowHidden()
+{
+  if ( STOPPED != mState )
+  {
+    Pause();
+
+    // Adaptor cannot be resumed until the window is shown
+    mState = PAUSED_WHILE_HIDDEN;
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::OnDamaged
+void Adaptor::OnDamaged( const DamageArea& area )
+{
+  // This is needed for the case where Dali window is partially obscured
+  RequestUpdate();
+}
+
+void Adaptor::SurfaceSizeChanged(const PositionSize& positionSize)
+{
+  // let the core know the surface size has changed
+  mCore->SurfaceResized(positionSize.width, positionSize.height);
+
+  mResizedSignal.Emit( mAdaptor );
+}
+
+void Adaptor::NotifySceneCreated()
+{
+  GetCore().SceneCreated();
+
+  // Start thread controller after the scene has been created
+  mThreadController->Start();
+}
+
+void Adaptor::NotifyLanguageChanged()
+{
+  mLanguageChangedSignal.Emit( mAdaptor );
+}
+
+void Adaptor::RequestUpdateOnce()
+{
+  if( PAUSED_WHILE_HIDDEN != mState )
+  {
+    if( mThreadController )
+    {
+      mThreadController->RequestUpdateOnce();
+    }
+  }
+}
+
+void Adaptor::ProcessCoreEventsFromIdle()
+{
+  ProcessCoreEvents();
+
+  // the idle handle automatically un-installs itself
+  mNotificationOnIdleInstalled = false;
+}
+
+Adaptor::Adaptor(Any nativeWindow, Dali::Adaptor& adaptor, RenderSurface* surface, EnvironmentOptions* environmentOptions)
+: mResizedSignal(),
+  mLanguageChangedSignal(),
+  mAdaptor(adaptor),
+  mState(READY),
+  mCore(NULL),
+  mThreadController(NULL),
+  mVSyncMonitor(NULL),
+  mGLES( NULL ),
+  mEglFactory( NULL ),
+  mNativeWindow( nativeWindow ),
+  mSurface( surface ),
+  mPlatformAbstraction( NULL ),
+  mEventHandler( NULL ),
+  mCallbackManager( NULL ),
+  mNotificationOnIdleInstalled( false ),
+  mNotificationTrigger(NULL),
+  mGestureManager(NULL),
+  mObservers(),
+  mDragAndDropDetector(),
+  mDeferredRotationObserver(NULL),
+  mEnvironmentOptions( environmentOptions ? environmentOptions : new EnvironmentOptions /* Create the options if not provided */),
+  mPerformanceInterface(NULL),
+  mObjectProfiler(NULL),
+  mEnvironmentOptionsOwned( environmentOptions ? false : true /* If not provided then we own the object */ )
+{
+  DALI_ASSERT_ALWAYS( !IsAvailable() && "Cannot create more than one Adaptor per thread" );
+  gThreadLocalAdaptor = this;
+}
+
+// Stereoscopy
+
+void Adaptor::SetViewMode( ViewMode viewMode )
+{
+  mSurface->SetViewMode( viewMode );
+  mCore->SetViewMode( viewMode );
+}
+
+ViewMode Adaptor::GetViewMode() const
+{
+  return mCore->GetViewMode();
+}
+
+void Adaptor::SetStereoBase( float stereoBase )
+{
+  mCore->SetStereoBase( stereoBase );
+}
+
+float Adaptor::GetStereoBase() const
+{
+  return mCore->GetStereoBase();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/adaptor-impl.h b/adaptors/common/adaptor-impl.h
new file mode 100644 (file)
index 0000000..e920459
--- /dev/null
@@ -0,0 +1,571 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_IMPL_H__
+#define __DALI_INTERNAL_ADAPTOR_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/view-mode.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/signals/callback.h>
+#include <dali/integration-api/render-controller.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <render-surface.h>
+#include <tts-player.h>
+#include <imf-manager.h>
+#include <clipboard.h>
+
+#include <tizen-platform-abstraction.h>
+#include <base/interfaces/adaptor-internal-services.h>
+#include <base/environment-options.h>
+#include <base/core-event-interface.h>
+#include <drag-and-drop-detector-impl.h>
+#include <damage-observer.h>
+#include <window-visibility-observer.h>
+#include <kernel-trace.h>
+#include <system-trace.h>
+#include <trigger-event-factory.h>
+#include <networking/socket-factory.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+class Window;
+
+namespace Integration
+{
+class Core;
+class GlAbstraction;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EventHandler;
+class EglFactory;
+class GestureManager;
+class GlImplementation;
+class GlSyncImplementation;
+class ThreadController;
+class TriggerEvent;
+class CallbackManager;
+class FeedbackPluginProxy;
+class FeedbackController;
+class RotationObserver;
+class VSyncMonitor;
+class PerformanceInterface;
+class LifeCycleObserver;
+class ObjectProfiler;
+
+/**
+ * Implementation of the Adaptor class.
+ */
+class Adaptor : public Integration::RenderController,
+                public AdaptorInternalServices,
+                public CoreEventInterface,
+                public DamageObserver,
+                public WindowVisibilityObserver
+{
+public:
+
+  typedef Dali::Adaptor::AdaptorSignalType AdaptorSignalType;
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  nativeWindow        Native window handle
+   * @param[in]  surface             A render surface can be one of the following
+   *                                  - Pixmap, adaptor will use existing Pixmap to draw on to
+   *                                  - Window, adaptor will use existing Window to draw on to
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( Any nativeWindow,
+                             RenderSurface* surface,
+                             Dali::Configuration::ContextLoss configuration,
+                             EnvironmentOptions* environmentOptions );
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  nativeWindow        native window handle
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( Dali::Window window, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions );
+
+  /**
+   * 2-step initialisation, this should be called after creating an adaptor instance.
+   */
+  void Initialize(Dali::Configuration::ContextLoss configuration);
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~Adaptor();
+
+  /**
+   * @copydoc Dali::Adaptor::Get()
+   */
+  static Dali::Adaptor& Get();
+
+  /**
+   * @copydoc Dali::Adaptor::IsAvailable()
+   */
+  static bool IsAvailable();
+
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
+public: // AdaptorInternalServices implementation
+  /**
+   * @copydoc Dali::Adaptor::Start()
+   */
+  virtual void Start();
+
+  /**
+   * @copydoc Dali::Adaptor::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc Dali::Adaptor::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc Dali::Adaptor::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc Dali::Adaptor::ContextLost()
+   */
+  virtual void ContextLost();
+
+  /**
+   * @copydoc Dali::Adaptor::ContextRegained()
+   */
+  virtual void ContextRegained();
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedTouchPoint()
+   */
+  virtual void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedWheelEvent()
+   */
+  virtual void FeedWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedKeyEvent()
+   */
+  virtual void FeedKeyEvent( KeyEvent& keyEvent );
+
+  /**
+   * @copydoc AdaptorInterface::MoveResize()
+   */
+  virtual bool MoveResize( const PositionSize& positionSize );
+
+  /**
+   * @copydoc AdaptorInterface::SurfaceResized()
+   */
+  virtual void SurfaceResized( const PositionSize& positionSize );
+
+  /**
+   * @copydoc AdaptorInterface::ReplaceSurface()
+   */
+  virtual void ReplaceSurface( Any nativeWindow, RenderSurface& surface );
+
+  /**
+   * @copydoc Dali::Adaptor::GetSurface()
+   */
+  virtual RenderSurface& GetSurface() const;
+
+  /**
+   * @copydoc Dali::Adaptor::ReleaseSurfaceLock()
+   */
+  virtual void ReleaseSurfaceLock();
+
+  /**
+   * Retrieve the TtsPlayer.
+   * @param[in] mode The mode of TtsPlayer
+   * @return A handle to the TtsPlayer.
+   */
+  virtual Dali::TtsPlayer GetTtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc Dali::Adaptor::AddIdle()
+   */
+  virtual bool AddIdle( CallbackBase* callback );
+
+public:
+
+  /**
+   * @return the Core instance
+   */
+  virtual Dali::Integration::Core& GetCore();
+
+  /**
+   * @copydoc Dali::Adaptor::SetRenderRefreshRate()
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * @copydoc Dali::Adaptor::SetUseHardwareVSync()
+   */
+  void SetUseHardwareVSync(bool useHardware);
+
+  /**
+   * @return reference to EglFactory class
+   */
+  EglFactory& GetEGLFactory() const;
+
+  /**
+   * Return GlAbstraction.
+   * @return the GlAbstraction.
+   */
+  Integration::GlAbstraction& GetGlAbstraction() const;
+
+  /**
+   * Return the PlatformAbstraction.
+   * @return The PlatformAbstraction.
+   */
+  Integration::PlatformAbstraction& GetPlatformAbstraction() const;
+
+  /**
+   * Sets the Drag & Drop Listener.
+   * @param[in] detector The detector to send Drag & Drop events to.
+   */
+  void SetDragAndDropDetector( DragAndDropDetectorPtr detector );
+
+  /**
+   * Sets a rotation observer, or set to NULL to remove.
+   * @pre Adaptor::Start() has been called ( to create EventHandler )
+   * @param[in] observer The observer to listen for window rotation events
+   */
+  void SetRotationObserver( RotationObserver* observer );
+
+  /**
+   * Destroy the TtsPlayer of sepcific mode.
+   * @param[in] mode The mode of TtsPlayer to destroy
+   */
+  void DestroyTtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @brief Sets minimum distance in pixels that the fingers must move towards/away from each other in order to
+   * trigger a pinch gesture
+   *
+   * @param[in] distance The minimum pinch distance in pixels
+   */
+  void SetMinimumPinchDistance(float distance);
+
+  /**
+   * Gets native window handle
+   *
+   * @return native window handle
+   */
+  Any GetNativeWindowHandle();
+
+public:
+
+  /**
+   * Adds an adaptor observer so that we can observe the adaptor's lifetime events.
+   * @param[in]  observer  The observer.
+   * @note Observers should remove themselves when they are destroyed.
+   */
+  void AddObserver( LifeCycleObserver& observer );
+
+  /**
+   * Removes the observer from the adaptor.
+   * @param[in]  observer  The observer to remove.
+   * @note Observers should remove themselves when they are destroyed.
+   */
+  void RemoveObserver( LifeCycleObserver& observer );
+
+  /**
+   * Emits the Notification event to the Dali core.
+   */
+  void SendNotificationEvent();
+
+  /**
+   * Request adaptor to update once
+   */
+  void RequestUpdateOnce();
+
+  /**
+   * @copydoc Dali::Adaptor::NotifySceneCreated()
+   */
+  void NotifySceneCreated();
+
+  /**
+   * @copydoc Dali::Adaptor::NotifyLanguageChanged()
+   */
+  void NotifyLanguageChanged();
+
+public:  //AdaptorInternalServices
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetPlatformAbstractionInterface()
+   */
+  virtual Dali::Integration::PlatformAbstraction& GetPlatformAbstractionInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetGlesInterface()
+   */
+  virtual Dali::Integration::GlAbstraction& GetGlesInterface();
+
+  /**
+  * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetEGLFactoryInterface()
+  */
+  virtual EglFactoryInterface& GetEGLFactoryInterface() const;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetTriggerEventInterface()
+   */
+  virtual TriggerEventInterface& GetProcessCoreEventsTrigger();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetTriggerEventFactoryInterface()
+   */
+  virtual TriggerEventFactoryInterface& GetTriggerEventFactoryInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetSocketFactoryInterface()
+   */
+  virtual SocketFactoryInterface& GetSocketFactoryInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetRenderSurfaceInterface()
+   */
+  virtual RenderSurface* GetRenderSurfaceInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetVSyncMonitorInterface()
+   */
+  virtual VSyncMonitorInterface* GetVSyncMonitorInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetPerformanceInterface()
+   */
+  virtual PerformanceInterface* GetPerformanceInterface();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetKernelTraceInterface()
+   */
+  virtual TraceInterface& GetKernelTraceInterface();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetSystemTraceInterface()
+   */
+  virtual TraceInterface& GetSystemTraceInterface();
+
+public: // Stereoscopy
+
+  /**
+   * @copydoc Dali::Integration::Core::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::Integration::Core::GetViewMode()
+   */
+  ViewMode GetViewMode() const;
+
+  /**
+   * @copydoc Dali::Integration::Core::SetStereoBase()
+   */
+  void SetStereoBase( float stereoBase );
+
+  /**
+   * @copydoc Dali::Integration::Core::GetStereoBase()
+   */
+  float GetStereoBase() const;
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Adaptor::SignalResized
+   */
+  AdaptorSignalType& ResizedSignal()
+  {
+    return mResizedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Adaptor::LanguageChangedSignal
+   */
+  AdaptorSignalType& LanguageChangedSignal()
+  {
+    return mLanguageChangedSignal;
+  }
+
+private: // From Dali::Internal::Adaptor::CoreEventInterface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::CoreEventInterface::QueueCoreEvent()
+   */
+  virtual void QueueCoreEvent(const Dali::Integration::Event& event);
+
+  /**
+   * @copydoc Dali::Internal::Adaptor:CoreEventInterface:::ProcessCoreEvents()
+   */
+  virtual void ProcessCoreEvents();
+
+private: // From Dali::Integration::RenderController
+
+  /**
+   * Called by the Dali core when it requires another update
+   */
+  virtual void RequestUpdate();
+
+  /**
+   * Called by Dali core when it requires an notification event being sent on idle.
+   * Multi-threading note: this method must be called from the main thread only.
+   */
+  virtual void RequestProcessEventsOnIdle();
+
+private: // From Dali::Internal::Adaptor::WindowVisibilityObserver
+
+  /**
+   * Called when the window becomes fully or partially visible.
+   */
+  virtual void OnWindowShown();
+
+  /**
+   * Called when the window is fully hidden.
+   */
+  virtual void OnWindowHidden();
+
+private: // From Dali::Internal::Adaptor::DamageObserver
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::DamageObserver::OnDamaged()
+   */
+  void OnDamaged( const DamageArea& area );
+
+private:
+
+  // Undefined
+  Adaptor(const Adaptor&);
+  Adaptor& operator=(Adaptor&);
+
+private:
+
+  /**
+   * Informs core the surface size has changed
+   */
+  void SurfaceSizeChanged(const PositionSize& positionSize);
+
+  /**
+   * Assigns the render surface to the adaptor
+   *
+   */
+  void SetSurface(RenderSurface *surface);
+
+  /**
+   * Sends an notification message from main loop idle handler
+   */
+  void ProcessCoreEventsFromIdle();
+
+  /**
+   * Gets path for data/resource storage.
+   * @param[out] path Path for data/resource storage
+   */
+  void GetDataStoragePath(std::string& path);
+
+private:
+
+  /**
+   * Constructor
+   * @param[in]  nativeWindow native window handle
+   * @param[in]  adaptor      The public adaptor
+   * @param[in]  surface      A render surface can be one of the following
+   *                          - Pixmap, adaptor will use existing Pixmap to draw on to
+   *                          - Window, adaptor will use existing Window to draw on to
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  Adaptor( Any nativeWindow, Dali::Adaptor& adaptor, RenderSurface* surface, EnvironmentOptions* environmentOptions );
+
+private: // Types
+
+  enum State
+  {
+    READY,               ///< Initial state before Adaptor::Start is called.
+    RUNNING,             ///< Adaptor is running.
+    PAUSED,              ///< Adaptor has been paused.
+    PAUSED_WHILE_HIDDEN, ///< Adaptor is paused while window is hidden (& cannot be resumed until window is shown).
+    STOPPED,             ///< Adaptor has been stopped.
+  };
+
+  typedef std::vector<LifeCycleObserver*>  ObserverContainer;
+
+private: // Data
+
+  AdaptorSignalType                     mResizedSignal;               ///< Resized signal.
+  AdaptorSignalType                     mLanguageChangedSignal;       ///< Language changed signal.
+
+  Dali::Adaptor&                        mAdaptor;                     ///< Reference to public adaptor instance.
+  State                                 mState;                       ///< Current state of the adaptor
+  Dali::Integration::Core*              mCore;                        ///< Dali Core
+  ThreadController*                     mThreadController;            ///< Controls the threads
+  VSyncMonitor*                         mVSyncMonitor;                ///< Monitors VSync events
+  GlImplementation*                     mGLES;                        ///< GL implementation
+  GlSyncImplementation*                 mGlSync;                      ///< GL Sync implementation
+  EglFactory*                           mEglFactory;                  ///< EGL Factory
+
+  Any                                   mNativeWindow;                ///< window identifier
+  RenderSurface*                        mSurface;                     ///< Current surface
+  TizenPlatform::TizenPlatformAbstraction*  mPlatformAbstraction;         ///< Platform abstraction
+
+  EventHandler*                         mEventHandler;                ///< event handler
+  CallbackManager*                      mCallbackManager;             ///< Used to install callbacks
+  bool                                  mNotificationOnIdleInstalled; ///< whether the idle handler is installed to send an notification event
+  TriggerEventInterface*                mNotificationTrigger;         ///< Notification event trigger
+  GestureManager*                       mGestureManager;              ///< Gesture manager
+  FeedbackPluginProxy*                  mDaliFeedbackPlugin;          ///< Used to access feedback support
+  FeedbackController*                   mFeedbackController;          ///< Plays feedback effects for Dali-Toolkit UI Controls.
+  Dali::TtsPlayer                       mTtsPlayers[Dali::TtsPlayer::MODE_NUM];                   ///< Provides TTS support
+  ObserverContainer                     mObservers;                   ///< A list of adaptor observer pointers
+  DragAndDropDetectorPtr                mDragAndDropDetector;         ///< The Drag & Drop detector
+  RotationObserver*                     mDeferredRotationObserver;    ///< deferred Rotation observer needs event handler
+  EnvironmentOptions*                   mEnvironmentOptions;          ///< environment options
+  PerformanceInterface*                 mPerformanceInterface;        ///< Performance interface
+  KernelTrace                           mKernelTracer;                ///< Kernel tracer
+  SystemTrace                           mSystemTracer;                ///< System tracer
+  TriggerEventFactory                   mTriggerEventFactory;         ///< Trigger event factory
+  ObjectProfiler*                       mObjectProfiler;              ///< Tracks object lifetime for profiling
+  SocketFactory                         mSocketFactory;               ///< Socket factory
+  const bool                            mEnvironmentOptionsOwned:1;   ///< Whether we own the EnvironmentOptions (and thus, need to delete it)
+public:
+  inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) {return *adaptor.mImpl;}
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_IMPL_H__
diff --git a/adaptors/common/adaptor.cpp b/adaptors/common/adaptor.cpp
new file mode 100644 (file)
index 0000000..e0af921
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <adaptor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <accessibility-adaptor.h>
+#include <imf-manager.h>
+#include <style-monitor.h>
+#include <render-surface.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+Adaptor& Adaptor::New( Window window )
+{
+  return New( window, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Window window, Configuration::ContextLoss configuration )
+{
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( window, configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor& Adaptor::New( Any nativeWindow, const Dali::RenderSurface& surface )
+{
+  return New( nativeWindow, surface, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Any nativeWindow, const Dali::RenderSurface& surface, Configuration::ContextLoss configuration )
+{
+  Dali::RenderSurface* pSurface = const_cast<Dali::RenderSurface *>(&surface);
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( nativeWindow, pSurface, configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor::~Adaptor()
+{
+  delete mImpl;
+}
+
+void Adaptor::Start()
+{
+  mImpl->Start();
+}
+
+void Adaptor::Pause()
+{
+  mImpl->Pause();
+}
+
+void Adaptor::Resume()
+{
+  mImpl->Resume();
+}
+
+void Adaptor::Stop()
+{
+  mImpl->Stop();
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback )
+{
+  return mImpl->AddIdle( callback );
+}
+
+void Adaptor::ReplaceSurface( Any nativeWindow, Dali::RenderSurface& surface )
+{
+  mImpl->ReplaceSurface(nativeWindow, surface);
+}
+
+Adaptor::AdaptorSignalType& Adaptor::ResizedSignal()
+{
+  return mImpl->ResizedSignal();
+}
+
+Adaptor::AdaptorSignalType& Adaptor::LanguageChangedSignal()
+{
+  return mImpl->LanguageChangedSignal();
+}
+
+RenderSurface& Adaptor::GetSurface()
+{
+  return mImpl->GetSurface();
+}
+
+void Adaptor::ReleaseSurfaceLock()
+{
+  mImpl->ReleaseSurfaceLock();
+}
+
+void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+  mImpl->SetRenderRefreshRate( numberOfVSyncsPerRender );
+}
+
+void Adaptor::SetUseHardwareVSync(bool useHardware)
+{
+  mImpl->SetUseHardwareVSync( useHardware );
+}
+
+Adaptor& Adaptor::Get()
+{
+  return Internal::Adaptor::Adaptor::Get();
+}
+
+bool Adaptor::IsAvailable()
+{
+  return Internal::Adaptor::Adaptor::IsAvailable();
+}
+
+void Adaptor::NotifySceneCreated()
+{
+  mImpl->NotifySceneCreated();
+}
+
+void Adaptor::NotifyLanguageChanged()
+{
+  mImpl->NotifyLanguageChanged();
+}
+
+void Adaptor::SetMinimumPinchDistance(float distance)
+{
+  mImpl->SetMinimumPinchDistance(distance);
+}
+
+void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  mImpl->FeedTouchPoint(point, timeStamp);
+}
+
+void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  mImpl->FeedWheelEvent(wheelEvent);
+}
+
+void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+{
+  mImpl->FeedKeyEvent(keyEvent);
+}
+
+void Adaptor::SceneCreated()
+{
+  mImpl->SceneCreated();
+}
+
+void Adaptor::SetViewMode( ViewMode mode )
+{
+  mImpl->SetViewMode( mode );
+}
+
+void Adaptor::SetStereoBase(  float stereoBase )
+{
+  mImpl->SetStereoBase( stereoBase );
+}
+
+
+Adaptor::Adaptor()
+: mImpl( NULL )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/common/application-impl.cpp b/adaptors/common/application-impl.cpp
new file mode 100644 (file)
index 0000000..f5c9965
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "application-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <style-monitor.h>
+#include <command-line-options.h>
+#include <common/adaptor-impl.h>
+#include <singleton-service-impl.h>
+#include <lifecycle-controller-impl.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+class TizenPlatformAbstraction;
+}
+
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+ApplicationPtr Application::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet,
+  Dali::Application::WINDOW_MODE windowMode)
+{
+  ApplicationPtr application ( new Application (argc, argv, stylesheet, windowMode ) );
+  return application;
+}
+
+Application::Application( int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode )
+: mInitSignal(),
+  mTerminateSignal(),
+  mPauseSignal(),
+  mResumeSignal(),
+  mResetSignal(),
+  mResizeSignal(),
+  mAppControlSignal(),
+  mLanguageChangedSignal(),
+  mRegionChangedSignal(),
+  mBatteryLowSignal(),
+  mMemoryLowSignal(),
+  mEventLoop( NULL ),
+  mFramework( NULL ),
+  mContextLossConfiguration( Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS ),
+  mCommandLineOptions( NULL ),
+  mSingletonService( SingletonService::New() ),
+  mAdaptor( NULL ),
+  mWindow(),
+  mWindowMode( windowMode ),
+  mName(),
+  mStylesheet( stylesheet ),
+  mEnvironmentOptions(),
+  mSlotDelegate( this )
+{
+  // Get mName from environment options
+  mName = mEnvironmentOptions.GetWindowName();
+  if( mName.empty() && argc && ( *argc > 0 ) )
+  {
+    // Set mName from command-line args if environment option not set
+    mName = (*argv)[0];
+  }
+
+  mCommandLineOptions = new CommandLineOptions(argc, argv);
+
+  mFramework = new Framework( *this, argc, argv );
+}
+
+Application::~Application()
+{
+  mSingletonService.UnregisterAll();
+
+  delete mFramework;
+  delete mCommandLineOptions;
+  delete mAdaptor;
+  mWindow.Reset();
+}
+
+void Application::CreateWindow()
+{
+  PositionSize windowPosition(0, 0, 0, 0);  // this will use full screen
+
+  if( mCommandLineOptions->stageWidth > 0 && mCommandLineOptions->stageHeight > 0 )
+  {
+    // Command line options override environment options and full screen
+    windowPosition = PositionSize( 0, 0, mCommandLineOptions->stageWidth, mCommandLineOptions->stageHeight );
+  }
+  else if( mEnvironmentOptions.GetWindowWidth() && mEnvironmentOptions.GetWindowHeight() )
+  {
+    // Environment options override full screen functionality if command line arguments not provided
+    windowPosition = PositionSize( 0, 0, mEnvironmentOptions.GetWindowWidth(), mEnvironmentOptions.GetWindowHeight() );
+  }
+
+  const std::string& windowClassName = mEnvironmentOptions.GetWindowClassName();
+  mWindow = Dali::Window::New( windowPosition, mName, windowClassName, mWindowMode == Dali::Application::TRANSPARENT );
+
+  // Quit the application when the window is closed
+  GetImplementation( mWindow ).DeleteRequestSignal().Connect( mSlotDelegate, &Application::Quit );
+}
+
+void Application::CreateAdaptor()
+{
+  DALI_ASSERT_ALWAYS( mWindow && "Window required to create adaptor" );
+
+  mAdaptor = Dali::Internal::Adaptor::Adaptor::New( mWindow, mContextLossConfiguration, &mEnvironmentOptions );
+
+  mAdaptor->ResizedSignal().Connect( mSlotDelegate, &Application::OnResize );
+}
+
+void Application::MainLoop(Dali::Configuration::ContextLoss configuration)
+{
+  mContextLossConfiguration = configuration;
+
+  // Run the application
+  mFramework->Run();
+}
+
+void Application::Lower()
+{
+  // Lower the application without quitting it.
+  mWindow.Lower();
+}
+
+void Application::Quit()
+{
+  // Actually quit the application.
+  AddIdle( MakeCallback( this, &Application::QuitFromMainLoop ) );
+}
+
+void Application::QuitFromMainLoop()
+{
+  mAdaptor->Stop();
+
+  Dali::Application application(this);
+  mTerminateSignal.Emit( application );
+
+  mFramework->Quit();
+  // This will trigger OnTerminate(), below, after the main loop has completed.
+}
+
+void Application::OnInit()
+{
+  mFramework->AddAbortCallback( MakeCallback( this, &Application::QuitFromMainLoop ) );
+
+  CreateWindow();
+  CreateAdaptor();
+
+  // Run the adaptor
+  mAdaptor->Start();
+
+  // Check if user requires no vsyncing and set on X11 Adaptor
+  if (mCommandLineOptions->noVSyncOnRender)
+  {
+    mAdaptor->SetUseHardwareVSync(false);
+  }
+
+  Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SetStereoBase( mCommandLineOptions->stereoBase );
+  if( mCommandLineOptions->viewMode != 0 )
+  {
+    ViewMode viewMode = MONO;
+    if( mCommandLineOptions->viewMode <= STEREO_INTERLACED )
+    {
+      viewMode = static_cast<ViewMode>( mCommandLineOptions->viewMode );
+    }
+    Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SetViewMode( viewMode );
+  }
+
+  if( ! mStylesheet.empty() )
+  {
+    Dali::StyleMonitor::Get().SetTheme( mStylesheet );
+  }
+
+  // Wire up the LifecycleController
+  Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
+
+  InitSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnInit );
+  TerminateSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnTerminate );
+  PauseSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnPause );
+  ResumeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResume );
+  ResetSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnReset );
+  ResizeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResize );
+  LanguageChangedSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnLanguageChanged );
+
+  Dali::Application application(this);
+  mInitSignal.Emit( application );
+
+  mAdaptor->NotifySceneCreated();
+}
+
+void Application::OnTerminate()
+{
+  // we've been told to quit by AppCore, ecore_x_destroy has been called, need to quit synchronously
+  // delete the window as ecore_x has been destroyed by AppCore
+
+  if( mAdaptor )
+  {
+    // Ensure that the render-thread is not using the surface(window) after we delete it
+    mAdaptor->Stop();
+  }
+
+  mWindow.Reset();
+
+  Dali::Application application(this);
+  mTerminateSignal.Emit( application );
+}
+
+void Application::OnPause()
+{
+  mAdaptor->Pause();
+  Dali::Application application(this);
+  mPauseSignal.Emit( application );
+}
+
+void Application::OnResume()
+{
+  // Emit the signal first so the application can queue any messages before we do an update/render
+  // This ensures we do not just redraw the last frame before pausing if that's not required
+  Dali::Application application(this);
+  mResumeSignal.Emit( application );
+  mAdaptor->Resume();
+}
+
+void Application::OnReset()
+{
+  /*
+   * usually, reset callback was called when a caller request to launch this application via aul.
+   * because Application class already handled initialization in OnInit(), OnReset do nothing.
+   */
+  Dali::Application application(this);
+  mResetSignal.Emit( application );
+
+  mWindow.Raise();
+}
+
+void Application::OnAppControl(void *data)
+{
+  Dali::Application application(this);
+  mAppControlSignal.Emit( application , data );
+}
+
+void Application::OnLanguageChanged()
+{
+  mAdaptor->NotifyLanguageChanged();
+  Dali::Application application(this);
+  mLanguageChangedSignal.Emit( application );
+}
+
+void Application::OnRegionChanged()
+{
+  Dali::Application application(this);
+  mRegionChangedSignal.Emit( application );
+}
+
+void Application::OnBatteryLow()
+{
+  Dali::Application application(this);
+  mBatteryLowSignal.Emit( application );
+}
+
+void Application::OnMemoryLow()
+{
+  Dali::Application application(this);
+  mMemoryLowSignal.Emit( application );
+}
+
+void Application::OnResize(Dali::Adaptor& adaptor)
+{
+  Dali::Application application(this);
+  mResizeSignal.Emit( application );
+}
+
+bool Application::AddIdle( CallbackBase* callback )
+{
+  return mAdaptor->AddIdle( callback );
+}
+
+Dali::Adaptor& Application::GetAdaptor()
+{
+  return *mAdaptor;
+}
+
+Dali::Window Application::GetWindow()
+{
+  return mWindow;
+}
+
+// Stereoscopy
+
+void Application::SetViewMode( ViewMode viewMode )
+{
+  Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SetViewMode( viewMode );
+}
+
+ViewMode Application::GetViewMode() const
+{
+  return Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).GetViewMode();
+}
+
+void Application::SetStereoBase( float stereoBase )
+{
+  Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).SetStereoBase( stereoBase );
+}
+
+float Application::GetStereoBase() const
+{
+  return Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).GetStereoBase();
+}
+
+
+void Application::ReplaceWindow(PositionSize windowPosition, const std::string& name)
+{
+  Dali::Window newWindow = Dali::Window::New( windowPosition, name, mWindowMode == Dali::Application::TRANSPARENT );
+  Window& windowImpl = GetImplementation(newWindow);
+  windowImpl.SetAdaptor(*mAdaptor);
+  newWindow.ShowIndicator(Dali::Window::INVISIBLE);
+  Dali::RenderSurface* renderSurface = windowImpl.GetSurface();
+
+  Any nativeWindow = newWindow.GetNativeHandle();
+  Internal::Adaptor::Adaptor::GetImplementation( *mAdaptor ).ReplaceSurface(nativeWindow, *renderSurface);
+  mWindow = newWindow;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/application-impl.h b/adaptors/common/application-impl.h
new file mode 100644 (file)
index 0000000..e323b0e
--- /dev/null
@@ -0,0 +1,340 @@
+#ifndef __DALI_INTERNAL_APPLICATION_H__
+#define __DALI_INTERNAL_APPLICATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <application.h>
+#include <singleton-service.h>
+
+#include <framework.h>
+#include <window-impl.h>
+#include <base/environment-options.h>
+
+namespace Dali
+{
+class Adaptor;
+class Window;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class CommandLineOptions;
+class EventLoop;
+
+typedef Dali::Rect<int> PositionSize;
+
+class Application;
+typedef IntrusivePtr<Application> ApplicationPtr;
+
+/**
+ * Implementation of the Application class.
+ */
+class Application : public BaseObject, public Framework::Observer
+{
+public:
+
+  typedef Dali::Application::AppSignalType AppSignalType;
+  typedef Dali::Application::AppControlSignalType AppControlSignalType;
+  typedef Dali::Application::WINDOW_MODE WINDOW_MODE;
+
+  /**
+   * Create a new application
+   * @param[in]  argc        A pointer to the number of arguments
+   * @param[in]  argv        A pointer to the argument list
+   * @param[in]  stylesheet  The path to user defined theme file
+   * @param[in]  windowMode  A member of Dali::Application::WINDOW_MODE
+   */
+  static ApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+public:
+
+  /**
+   * @copydoc Dali::Application::MainLoop()
+   */
+  void MainLoop(Dali::Configuration::ContextLoss configuration);
+
+  /**
+   * @copydoc Dali::Application::Lower()
+   */
+  void Lower();
+
+  /**
+   * @copydoc Dali::Application::Quit()
+   */
+  void Quit();
+
+  /**
+   * @copydoc Dali::Application::AddIdle()
+   */
+  bool AddIdle( CallbackBase* callback );
+
+  /**
+   * @copydoc Dali::Application::GetAdaptor();
+   */
+  Dali::Adaptor& GetAdaptor();
+
+  /**
+   * @copydoc Dali::Application::GetWindow();
+   */
+  Dali::Window GetWindow();
+
+  /**
+   * @copydoc Dali::Application::ReplaceWindow();
+   */
+  void ReplaceWindow(PositionSize windowPosition, const std::string& name);
+
+public: // Stereoscopy
+
+  /**
+   * @copydoc Dali::Application::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::Application::GetViewMode()
+   */
+  ViewMode GetViewMode() const;
+
+  /**
+   * @copydoc Dali::Application::SetStereoBase()
+   */
+  void SetStereoBase( float stereoBase );
+
+  /**
+   * @copydoc Dali::Application::GetStereoBase()
+   */
+  float GetStereoBase() const;
+
+public: // From Framework::Observer
+
+  /**
+   * Called when the framework is initialised.
+   */
+  virtual void OnInit();
+
+  /**
+   * Called when the framework is terminated.
+   */
+  virtual void OnTerminate();
+
+  /**
+   * Called when the framework is paused.
+   */
+  virtual void OnPause();
+
+  /**
+   * Called when the framework resumes from a paused state.
+   */
+  virtual void OnResume();
+
+  /**
+  * Called when the framework received AppControlSignal.
+  * @param[in] The bundle data of AppControl event.
+  */
+  virtual void OnAppControl(void *data);
+
+  /**
+   * Called when the framework informs the application that it should reset itself.
+   */
+  virtual void OnReset();
+
+  /**
+   * Called when the framework informs the application that the language of the device has changed.
+   */
+  virtual void OnLanguageChanged();
+
+  /**
+  * Called when the framework informs the application that the region of the device has changed.
+  */
+  virtual void OnRegionChanged();
+
+  /**
+  * Called when the framework informs the application that the battery level of the device is low.
+  */
+  virtual void OnBatteryLow();
+
+  /**
+  * Called when the framework informs the application that the memory level of the device is low.
+  */
+  virtual void OnMemoryLow();
+
+public:
+
+  /**
+   * Signal handler when the adaptor's window resizes itself.
+   * @param[in]  adaptor  The adaptor
+   */
+  void OnResize(Dali::Adaptor& adaptor);
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::Application::InitSignal()
+   */
+  Dali::Application::AppSignalType& InitSignal() { return mInitSignal; }
+
+  /**
+   * @copydoc Dali::Application::TerminateSignal()
+   */
+  Dali::Application::AppSignalType& TerminateSignal() { return mTerminateSignal; }
+
+  /**
+   * @copydoc Dali::Application::PauseSignal()
+   */
+  Dali::Application::AppSignalType& PauseSignal() { return mPauseSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResumeSignal()
+   */
+  Dali::Application::AppSignalType& ResumeSignal() { return mResumeSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResetSignal()
+   */
+  Dali::Application::AppSignalType& ResetSignal() { return mResetSignal; }
+
+  /**
+  * @copydoc Dali::Application::AppControlSignal()
+  */
+  Dali::Application::AppControlSignalType& AppControlSignal() { return mAppControlSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResizeSignal()
+   */
+  Dali::Application::AppSignalType& ResizeSignal() { return mResizeSignal; }
+
+  /**
+   * @copydoc Dali::Application::LanguageChangedSignal()
+   */
+  Dali::Application::AppSignalType& LanguageChangedSignal() { return mLanguageChangedSignal; }
+
+  /**
+  * @copydoc Dali::Application::RegionChangedSignal()
+  */
+  Dali::Application::AppSignalType& RegionChangedSignal() { return mRegionChangedSignal; }
+
+  /**
+  * @copydoc Dali::Application::BatteryLowSignal()
+  */
+  Dali::Application::AppSignalType& BatteryLowSignal() { return mBatteryLowSignal; }
+
+  /**
+  * @copydoc Dali::Application::MemoryLowSignal()
+  */
+  Dali::Application::AppSignalType& MemoryLowSignal() { return mMemoryLowSignal; }
+
+private:
+
+  /**
+   * Private Constructor
+   * @param[in]  argc        A pointer to the number of arguments
+   * @param[in]  argv        A pointer to the argument list
+   * @param[in]  stylesheet  The path to user defined theme file
+   * @param[in]  windowMode  A member of Dali::Application::WINDOW_MODE
+   */
+  Application( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+  /**
+   * Destructor
+   */
+  virtual ~Application();
+
+  // Undefined
+  Application(const Application&);
+  Application& operator=(Application&);
+
+private:
+  /**
+   * Creates the window
+   */
+  void CreateWindow();
+
+  /**
+   * Creates the adaptor
+   */
+  void CreateAdaptor();
+
+  /**
+   * Quits from the main loop
+   */
+  void QuitFromMainLoop();
+
+private:
+
+  AppSignalType                           mInitSignal;
+  AppSignalType                           mTerminateSignal;
+  AppSignalType                           mPauseSignal;
+  AppSignalType                           mResumeSignal;
+  AppSignalType                           mResetSignal;
+  AppSignalType                           mResizeSignal;
+  AppControlSignalType                    mAppControlSignal;
+  AppSignalType                           mLanguageChangedSignal;
+  AppSignalType                           mRegionChangedSignal;
+  AppSignalType                           mBatteryLowSignal;
+  AppSignalType                           mMemoryLowSignal;
+
+  EventLoop*                            mEventLoop;
+  Framework*                            mFramework;
+
+  Dali::Configuration::ContextLoss      mContextLossConfiguration;
+  CommandLineOptions*                   mCommandLineOptions;
+
+  Dali::SingletonService                mSingletonService;
+  Dali::Adaptor*                        mAdaptor;
+  Dali::Window                          mWindow;
+  Dali::Application::WINDOW_MODE        mWindowMode;
+  std::string                           mName;
+  std::string                           mStylesheet;
+  EnvironmentOptions                    mEnvironmentOptions;
+
+  SlotDelegate< Application >           mSlotDelegate;
+};
+
+inline Application& GetImplementation(Dali::Application& application)
+{
+  DALI_ASSERT_ALWAYS(application && "application handle is empty");
+
+  BaseObject& handle = application.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Application&>(handle);
+}
+
+inline const Application& GetImplementation(const Dali::Application& application)
+{
+  DALI_ASSERT_ALWAYS(application && "Timre handle is empty");
+
+  const BaseObject& handle = application.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Application&>(handle);
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_APPLICATION_H__
diff --git a/adaptors/common/bitmap-loader-impl.cpp b/adaptors/common/bitmap-loader-impl.cpp
new file mode 100644 (file)
index 0000000..69505df
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/integration-api/resource-types.h>
+#include <dali/integration-api/resource-cache.h>
+
+// INTERNAL INCLUDES
+#include "bitmap-loader-impl.h"
+#include "image-loaders/image-loader.h"
+
+namespace Dali
+{
+namespace Internal
+{
+
+IntrusivePtr<BitmapLoader> BitmapLoader::New(const std::string& filename)
+{
+  IntrusivePtr<BitmapLoader> internal = new BitmapLoader();
+  internal->Initialize(filename);
+  return internal;
+}
+
+BitmapLoader::BitmapLoader()
+: mBitmap(NULL)
+{
+}
+
+BitmapLoader::~BitmapLoader()
+{
+}
+
+void BitmapLoader::Initialize(const std::string& filename)
+{
+  // Load with default scaling and orientation correction:
+  Integration::BitmapResourceType bitmapResourceType;
+  Integration::ResourcePointer resource = TizenPlatform::ImageLoader::LoadResourceSynchronously( bitmapResourceType, filename );
+
+  mBitmap = static_cast<Integration::Bitmap*>(resource.Get());
+}
+
+unsigned char* BitmapLoader::GetPixelData() const
+{
+  return mBitmap->GetBuffer();
+}
+
+unsigned int BitmapLoader::GetImageHeight() const
+{
+  return mBitmap->GetImageHeight();
+}
+
+unsigned int BitmapLoader::GetImageWidth() const
+{
+  return mBitmap->GetImageWidth();
+}
+
+unsigned int BitmapLoader::GetBufferStride() const
+{
+  return mBitmap->GetPackedPixelsProfile()->GetBufferStride();
+}
+
+Pixel::Format BitmapLoader::GetPixelFormat() const
+{
+  return mBitmap->GetPixelFormat();
+}
+
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/common/bitmap-loader-impl.h b/adaptors/common/bitmap-loader-impl.h
new file mode 100644 (file)
index 0000000..c9f8ff4
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef __DALI_BITMAP_LOADER_IMPL_H__
+#define __DALI_BITMAP_LOADER_IMPL_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/integration-api/bitmap.h>
+
+// INTERNAL INCLUDES
+#include <bitmap-loader.h>
+
+namespace Dali
+{
+namespace Internal
+{
+
+class BitmapLoader : public BaseObject
+{
+public:
+  static IntrusivePtr<BitmapLoader> New(const std::string& filename);
+
+  /**
+   * Create the bitmap loader object.
+   */
+  BitmapLoader();
+
+protected:
+  /**
+   * Destructor
+   */
+  ~BitmapLoader();
+
+  /**
+   * Second stage initialization - this will load the image synchronously.
+   * @param[in] filename  Filename of the bitmap image to load.
+   */
+  void Initialize(const std::string& filename);
+
+public:
+
+  /**
+   * Get the raw pixel data.
+   * @return The pixel data. Use the GetHeight(), GetWidth(), GetStride() and GetPixelFormat() methods
+   * to decode the data.
+   */
+  unsigned char* GetPixelData() const;
+
+  /**
+   * Get the buffer height in pixels
+   * @return the height of the buffer in pixels
+   */
+  unsigned int GetImageHeight() const;
+
+  /**
+   * Get the buffer width in pixels
+   * @return the width of the buffer in pixels
+   */
+  unsigned int GetImageWidth() const;
+
+  /**
+   * Get the number of bytes in each row of pixels
+   * @return The buffer stride in bytes.
+   */
+  unsigned int GetBufferStride() const;
+
+  /**
+   * Get the pixel format of the loaded bitmap.
+   */
+  Pixel::Format GetPixelFormat() const;
+
+private:
+  Integration::BitmapPtr mBitmap;
+};
+
+} // Internal
+
+
+inline Internal::BitmapLoader& GetImplementation(Dali::BitmapLoader& handle)
+{
+  DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+
+  BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<Internal::BitmapLoader&>(object);
+}
+
+inline const Internal::BitmapLoader& GetImplementation(const Dali::BitmapLoader& handle)
+{
+  DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+
+  const BaseObject& object = handle.GetBaseObject();
+
+  return static_cast<const Internal::BitmapLoader&>(object);
+}
+
+} // Dali
+
+#endif // __DALI_BITMAP_LOADER_IMPL_H__
diff --git a/adaptors/common/callback-manager.h b/adaptors/common/callback-manager.h
new file mode 100644 (file)
index 0000000..20f8798
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef __DALI_INTERNAL_CALLBACK_MANAGER_H__
+#define __DALI_INTERNAL_CALLBACK_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract interface to install call backs in to an applications main loop.
+ */
+class CallbackManager
+{
+
+public:
+
+    /**
+     * Create a new call back interface
+     */
+    static CallbackManager* New();
+
+    /**
+     * Virtual destructor
+     */
+    virtual ~CallbackManager() {}
+
+    /**
+     * Adds a call back to be run on idle.
+     * Must be call from main thread only.
+     * @param callback custom call back function
+     * @param priority call back priority
+     * @return true on success
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback ) = 0;
+
+    /**
+     * Starts the callback manager.
+     */
+    virtual void Start() = 0;
+
+    /**
+     * Stop the callback manager and can remove all pending callbacks synchronously.
+     * This call will synchronise with the main loop and not return
+     * until all call backs have been deleted.
+     */
+    virtual void Stop() = 0;
+
+protected:
+
+    /**
+     * constructor
+     */
+    CallbackManager() {}
+
+private:
+
+    // Undefined copy constructor.
+    CallbackManager( const CallbackManager& );
+
+    // Undefined assignment operator.
+    CallbackManager& operator=( const CallbackManager& );
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CALLBACK_MANAGER_H__
diff --git a/adaptors/common/clipboard-event-notifier-impl.cpp b/adaptors/common/clipboard-event-notifier-impl.cpp
new file mode 100644 (file)
index 0000000..981ac46
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "clipboard-event-notifier-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+BaseHandle Create()
+{
+  BaseHandle handle( ClipboardEventNotifier::Get() );
+
+  if ( !handle )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Dali::ClipboardEventNotifier notifier( ClipboardEventNotifier::New() );
+      service.Register( typeid( notifier ), notifier );
+      handle = notifier;
+    }
+  }
+
+  return handle;
+}
+TypeRegistration CLIPBOARD_EVENT_NOTIFIER_TYPE( typeid(Dali::ClipboardEventNotifier), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::New()
+{
+  Dali::ClipboardEventNotifier notifier = Dali::ClipboardEventNotifier(new ClipboardEventNotifier());
+
+  return notifier;
+}
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  Dali::ClipboardEventNotifier notifier;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ClipboardEventNotifier ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      notifier = Dali::ClipboardEventNotifier( dynamic_cast< ClipboardEventNotifier* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return notifier;
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return mContent;
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  mContent = content;
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  mContent.clear();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  if ( !mContentSelectedSignal.Empty() )
+  {
+    Dali::ClipboardEventNotifier handle( this );
+    mContentSelectedSignal.Emit( handle );
+  }
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+: mContent()
+{
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/clipboard-event-notifier-impl.h b/adaptors/common/clipboard-event-notifier-impl.h
new file mode 100644 (file)
index 0000000..db51291
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef __DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H__
+#define __DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <clipboard-event-notifier.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This class listens to Clipboard events.
+ */
+class ClipboardEventNotifier : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::ClipboardEventNotifier::ClipboardEventSignalType ClipboardEventSignalType;
+
+  // Creation
+
+  /**
+   * Create a ClipboardEventNotifier.
+   * @return A newly allocated clipboard-event-notifier.
+   */
+  static Dali::ClipboardEventNotifier New();
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::ClipboardEventNotifier Get();
+
+  // Public API
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::GetContent() const
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * Sets the selected content.
+   * @param[in] content  A string that represents the content that has been selected.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * Called when content is selected in the clipboard.
+   */
+  void EmitContentSelectedSignal();
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::ContentSelectedSignal
+   */
+  ClipboardEventSignalType& ContentSelectedSignal()
+  {
+    return mContentSelectedSignal;
+  }
+
+private:
+
+  // Construction & Destruction
+
+  /**
+   * Constructor.
+   */
+  ClipboardEventNotifier();
+
+  /**
+   * Destructor.
+   */
+  virtual ~ClipboardEventNotifier();
+
+  // Undefined
+  ClipboardEventNotifier( const ClipboardEventNotifier& );
+  ClipboardEventNotifier& operator=( ClipboardEventNotifier& );
+
+private:
+
+  std::string mContent;    ///< The current selected content.
+
+  ClipboardEventSignalType mContentSelectedSignal;
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::ClipboardEventNotifier& GetImplementation(Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+  inline static const Internal::Adaptor::ClipboardEventNotifier& GetImplementation(const Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    const BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H__
diff --git a/adaptors/common/color-controller-impl.cpp b/adaptors/common/color-controller-impl.cpp
new file mode 100644 (file)
index 0000000..7e5a1fe
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "color-controller-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::ColorController ColorController::Get()
+{
+  return Dali::ColorController( new ColorController() );
+}
+
+ColorController::ColorController()
+{
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return false;
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/color-controller-impl.h b/adaptors/common/color-controller-impl.h
new file mode 100644 (file)
index 0000000..eb7d552
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __DALI_INTERNAL_COLOR_CONTROLLER_H__
+#define __DALI_INTERNAL_COLOR_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <color-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of ColorController
+ */
+class ColorController : public BaseObject
+{
+public:
+
+  /**
+   * Constructor.
+   */
+  ColorController();
+
+  /**
+   * @copydoc Dali::ColorController::Get()
+   */
+  static Dali::ColorController Get();
+
+  /**
+   * @copydoc Dali::ColorController::RetrieveColor(const std::string&, Vector4&)
+   */
+  bool RetrieveColor( const std::string& colorCode, Vector4& colorValue );
+
+  /**
+   *copydoc Dali::ColorController::RetrieveColor(const std::string&, Vector4&, Vector4&, Vector4&)
+   */
+  bool RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor);
+
+protected:
+  /**
+   * Destructor.
+   */
+  virtual ~ColorController();
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+inline Internal::Adaptor::ColorController& GetImplementation(Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  BaseObject& handle = controller.GetBaseObject();
+  return static_cast<Internal::Adaptor::ColorController&>(handle);
+}
+
+inline const Internal::Adaptor::ColorController& GetImplementation(const Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  const BaseObject& handle = controller.GetBaseObject();
+  return static_cast<const Internal::Adaptor::ColorController&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_COLOR_CONTROLLER_H__
diff --git a/adaptors/common/command-line-options.cpp b/adaptors/common/command-line-options.cpp
new file mode 100644 (file)
index 0000000..921314a
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "command-line-options.h"
+
+// EXTERNAL INCLUDES
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+#include <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+struct Argument
+{
+  const char * const opt;
+  const char * const optDescription;
+
+  void Print()
+  {
+    const std::ios_base::fmtflags flags = std::cout.flags();
+    std::cout << std::left << "  --";
+    std::cout.width( 18 );
+    std::cout << opt;
+    std::cout << optDescription;
+    std::cout << std::endl;
+    std::cout.flags( flags );
+  }
+};
+
+Argument EXPECTED_ARGS[] =
+{
+  { "no-vsync",    "Disable VSync on Render" },
+  { "width",       "Stage Width"             },
+  { "height",      "Stage Height"            },
+  { "dpi",         "Emulated DPI"            },
+  { "view",        "Stereocopic 3D view mode ([0]=MONO, 1=STEREO_HORZ, 2=STEREO_VERT, 3=STEREO_INTERLACED)" },
+  { "stereo-base", "Distance in millimeters between left/right cameras [65.0]" },
+  { "help",        "Help"                    },
+  { NULL,          NULL                      }
+};
+
+enum Option
+{
+  OPTION_NO_VSYNC = 0,
+  OPTION_STAGE_WIDTH,
+  OPTION_STAGE_HEIGHT,
+  OPTION_DPI,
+  OPTION_STEREO_MODE,
+  OPTION_STEREO_BASE,
+  OPTION_HELP
+};
+
+typedef Dali::Vector< int > UnhandledContainer;
+
+void ShowHelp()
+{
+  std::cout << "Available options:" << std::endl;
+  Argument* arg = EXPECTED_ARGS;
+  while ( arg->opt )
+  {
+    arg->Print();
+    ++arg;
+  }
+}
+
+} // unnamed namespace
+
+CommandLineOptions::CommandLineOptions(int *argc, char **argv[])
+: noVSyncOnRender(0),
+  stageWidth(0), stageHeight(0),
+  viewMode(0),
+  stereoBase(65)
+{
+  // Exit gracefully if no arguments provided
+  if ( !argc || !argv )
+  {
+    return;
+  }
+
+  if ( *argc > 1 )
+  {
+    // We do not want to print out errors.
+    int origOptErrValue( opterr );
+    opterr = 0;
+
+    int help( 0 );
+
+    const struct option options[]=
+    {
+      { EXPECTED_ARGS[OPTION_NO_VSYNC].opt,     no_argument,       &noVSyncOnRender, 1   },  // "--no-vsync"
+      { EXPECTED_ARGS[OPTION_STAGE_WIDTH].opt,  required_argument, NULL,             'w' },  // "--width"
+      { EXPECTED_ARGS[OPTION_STAGE_HEIGHT].opt, required_argument, NULL,             'h' },  // "--height"
+      { EXPECTED_ARGS[OPTION_DPI].opt,          required_argument, NULL,             'd' },  // "--dpi"
+      { EXPECTED_ARGS[OPTION_STEREO_MODE].opt,  required_argument, NULL,             'v' },  // "--view"
+      { EXPECTED_ARGS[OPTION_STEREO_BASE].opt,  required_argument, NULL,             's' },  // "--stereo-base"
+      { EXPECTED_ARGS[OPTION_HELP].opt,         no_argument,       &help,            '?' },  // "--help"
+      { 0, 0, 0, 0 } // end of options
+    };
+
+    int shortOption( 0 );
+    int optionIndex( 0 );
+
+    const char* optString = "-w:h:d:v:s:"; // The '-' ensures that argv is NOT permuted
+    bool optionProcessed( false );
+
+    UnhandledContainer unhandledOptions; // We store indices of options we do not handle here
+
+    do
+    {
+      shortOption = getopt_long( *argc, *argv, optString, options, &optionIndex );
+
+      switch ( shortOption )
+      {
+        case 0:
+        {
+          // Check if we want help
+          if ( help )
+          {
+            ShowHelp();
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'w':
+        {
+          if ( optarg )
+          {
+            stageWidth = atoi( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'h':
+        {
+          if ( optarg )
+          {
+            stageHeight = atoi( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'd':
+        {
+          if ( optarg )
+          {
+            stageDPI.assign( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'v':
+        {
+          if ( optarg )
+          {
+            viewMode = atoi(optarg);
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 's':
+        {
+          if ( optarg )
+          {
+            stereoBase = atoi(optarg);
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case -1:
+        {
+          // All command-line options have been parsed.
+          break;
+        }
+
+        default:
+        {
+          unhandledOptions.PushBack( optind - 1 );
+          break;
+        }
+      }
+    } while ( shortOption != -1 );
+
+    // Take out the options we have processed
+    if ( optionProcessed )
+    {
+      if ( unhandledOptions.Count() > 0 )
+      {
+        int index( 1 );
+
+        // Overwrite the argv with the values from the unhandled indices
+        const UnhandledContainer::ConstIterator endIter = unhandledOptions.End();
+        for ( UnhandledContainer::Iterator iter = unhandledOptions.Begin(); iter != endIter; ++iter )
+        {
+          (*argv)[ index++ ] = (*argv)[ *iter ];
+        }
+        *argc = unhandledOptions.Count() + 1; // +1 for the program name
+      }
+      else
+      {
+        // There are no unhandled options, so we should just have the program name
+        *argc = 1;
+      }
+
+      optind = 1; // Reset to start
+    }
+
+    opterr = origOptErrValue; // Reset opterr value.
+  }
+}
+
+CommandLineOptions::~CommandLineOptions()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/command-line-options.h b/adaptors/common/command-line-options.h
new file mode 100644 (file)
index 0000000..9067dc1
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __DALI_INTERNAL_COMMAND_LINE_OPTIONS_H__
+#define __DALI_INTERNAL_COMMAND_LINE_OPTIONS_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Parses the passed command line arguments and sets the values stored within this
+ * class appropriately.
+ *
+ * The following options are supported:
+ *
+ * @code
+ *     --no-vsync       Disable VSync on Render
+ *  -w|--width          Stage Width
+ *  -h|--height         Stage Height
+ *  -d|--dpi            Emulated DPI
+ *  -v|--view           Viewing mode
+ *  -s|--stereo-base    Eye separation for stereoscopic rendering (in mm)
+ *     --help           Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
+ */
+struct CommandLineOptions
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in,out]  argc  The number of arguments
+   * @param[in,out]  argv  The argument list
+   * @note Supported options are stripped from argv, and argc is updated appropriately.
+   */
+  CommandLineOptions(int *argc, char **argv[]);
+
+  /**
+   * Destructor
+   */
+  ~CommandLineOptions();
+
+public: // Command line parsed values
+
+  int noVSyncOnRender;  ///< If 1, then the user does not want VSync on Render
+  int stageWidth;       ///< The width of the stage required.  0 if not set.
+  int stageHeight;      ///< The height of the stage required.   0 if not set.
+  int viewMode;         ///< Stereocopic 3D view mode (0=MONO, 1=STEREO_HORZ, 2=STEREO_VERT, 3=STEREO_INTERLACED)
+  int stereoBase;       ///< The distance in millimeters between left/right cameras
+  std::string stageDPI; ///< DPI stored as hxv, where h is horizontal DPI and v is vertical DPI
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_COMMAND_LINE_OPTIONS_H__
diff --git a/adaptors/common/damage-observer.h b/adaptors/common/damage-observer.h
new file mode 100644 (file)
index 0000000..d0a2316
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __DALI_INTERNAL_DAMAGE_OBSERVER_H__
+#define __DALI_INTERNAL_DAMAGE_OBSERVER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/rect.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+typedef Rect<int> DamageArea;
+
+/**
+ * The DamageObserver can be overridden in order to listen to damage events.
+ */
+class DamageObserver
+{
+public:
+
+  /**
+   * Deriving classes should override this to be notified when we receive a damage event.
+   * @param[in]  area  The area that has been damaged.
+   */
+  virtual void OnDamaged( const DamageArea& area ) = 0;
+
+protected:
+
+  /**
+   * Protected Constructor.
+   */
+  DamageObserver()
+  {
+  }
+
+  /**
+   * Protected virtual destructor.
+   */
+  virtual ~DamageObserver()
+  {
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_DAMAGE_OBSERVER_H__
diff --git a/adaptors/common/drag-and-drop-detector-impl.cpp b/adaptors/common/drag-and-drop-detector-impl.cpp
new file mode 100644 (file)
index 0000000..b37166a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "drag-and-drop-detector-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::DragAndDropDetector DragAndDropDetector::New()
+{
+  Dali::DragAndDropDetector detector = Dali::DragAndDropDetector(new DragAndDropDetector());
+
+  return detector;
+}
+
+const std::string& DragAndDropDetector::GetContent() const
+{
+  return mContent;
+}
+
+Vector2 DragAndDropDetector::GetCurrentScreenPosition() const
+{
+  return mScreenPosition;
+}
+
+bool DragAndDropDetector::IsEnabled() const
+{
+  return !mDroppedSignal.Empty() || !mEnteredSignal.Empty() || !mExitedSignal.Empty() || !mMovedSignal.Empty() ;
+}
+
+void DragAndDropDetector::SetContent( const std::string& content )
+{
+  mContent = content;
+}
+
+void DragAndDropDetector::ClearContent()
+{
+  mContent.clear();
+}
+
+void DragAndDropDetector::SetPosition( Vector2 screenPosition )
+{
+  mScreenPosition = screenPosition;
+}
+
+void DragAndDropDetector::EmitEnteredSignal()
+{
+  if ( !mEnteredSignal.Empty() )
+  {
+    Dali::DragAndDropDetector handle( this );
+    mEnteredSignal.Emit( handle );
+  }
+}
+
+void DragAndDropDetector::EmitExitedSignal()
+{
+  if ( !mExitedSignal.Empty() )
+  {
+    Dali::DragAndDropDetector handle( this );
+    mExitedSignal.Emit( handle );
+  }
+}
+
+void DragAndDropDetector::EmitMovedSignal()
+{
+  if ( !mMovedSignal.Empty() )
+  {
+    Dali::DragAndDropDetector handle( this );
+    mMovedSignal.Emit( handle );
+  }
+}
+
+void DragAndDropDetector::EmitDroppedSignal()
+{
+  if ( !mDroppedSignal.Empty() )
+  {
+    Dali::DragAndDropDetector handle( this );
+    mDroppedSignal.Emit( handle );
+  }
+}
+
+DragAndDropDetector::DragAndDropDetector()
+: mContent(),
+  mScreenPosition()
+{
+}
+
+DragAndDropDetector::~DragAndDropDetector()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/drag-and-drop-detector-impl.h b/adaptors/common/drag-and-drop-detector-impl.h
new file mode 100644 (file)
index 0000000..d4a1395
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef __DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H__
+#define __DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <drag-and-drop-detector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+typedef IntrusivePtr< DragAndDropDetector > DragAndDropDetectorPtr;
+
+/**
+ * This class listens to Drag & Drop events.
+ */
+class DragAndDropDetector : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::DragAndDropDetector::DragAndDropSignal DragAndDropSignal;
+
+  // Creation
+
+  /**
+   * Create a DragAndDropDetector.
+   * This should only be called once by the Window class.
+   * @return A newly allocated drag-and-drop-detector.
+   */
+  static Dali::DragAndDropDetector New();
+
+  // Public API
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::GetContent() const
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::GetCurrentScreenPosition() const
+   */
+  Vector2 GetCurrentScreenPosition() const;
+
+  // Called by Drag & Drop Event Handler
+
+  /**
+   * Queries whether drag & drop behaviour is really required.
+   * @return true if drag & drop required, false otherwise.
+   */
+  bool IsEnabled() const;
+
+  /**
+   * Sets the dragged content.
+   * @param[in] content  A string that represents the content that has been dropped.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * Sets the position the drop occurred.
+   */
+  void SetPosition( Vector2 screenPosition );
+
+  /**
+   * Called when a draggable object enters our window.
+   */
+  void EmitEnteredSignal();
+
+  /**
+   * Called when a draggable object leaves our window.
+   */
+  void EmitExitedSignal();
+
+  /**
+   * Called when a draggable object leaves our window.
+   */
+  void EmitMovedSignal();
+
+  /**
+   * Is called when a drop actually occurs.
+   */
+  void EmitDroppedSignal();
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::EnteredSignal
+   */
+  DragAndDropSignal& EnteredSignal()
+  {
+    return mEnteredSignal;
+  }
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::ExitedSignal
+   */
+  DragAndDropSignal& ExitedSignal()
+  {
+    return mExitedSignal;
+  }
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::MovedSignal
+   */
+  DragAndDropSignal& MovedSignal()
+  {
+    return mMovedSignal;
+  }
+
+  /**
+   * @copydoc Dali::DragAndDropDetector::DroppedSignal
+   */
+  DragAndDropSignal& DroppedSignal()
+  {
+    return mDroppedSignal;
+  }
+
+private:
+
+  // Construction & Destruction
+
+  /**
+   * Constructor.
+   */
+  DragAndDropDetector();
+
+  /**
+   * Destructor.
+   */
+  virtual ~DragAndDropDetector();
+
+  // Undefined
+  DragAndDropDetector( const DragAndDropDetector& );
+  DragAndDropDetector& operator=( DragAndDropDetector& );
+
+private:
+
+  std::string mContent;    ///< The current Drag & drop content.
+  Vector2 mScreenPosition; ///< The screen position of the drop location.
+
+  DragAndDropSignal mEnteredSignal;
+  DragAndDropSignal mExitedSignal;
+  DragAndDropSignal mMovedSignal;
+  DragAndDropSignal mDroppedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::DragAndDropDetector& GetImplementation(Dali::DragAndDropDetector& detector)
+{
+  DALI_ASSERT_ALWAYS( detector && "DragAndDropDetector handle is empty" );
+
+  BaseObject& handle = detector.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::DragAndDropDetector&>(handle);
+}
+
+inline const Internal::Adaptor::DragAndDropDetector& GetImplementation(const Dali::DragAndDropDetector& detector)
+{
+  DALI_ASSERT_ALWAYS( detector && "DragAndDropDetector handle is empty" );
+
+  const BaseObject& handle = detector.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::DragAndDropDetector&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_DRAG_AND_DROP_DETECTOR_H__
diff --git a/adaptors/common/event-loop/ecore/ecore-callback-manager.cpp b/adaptors/common/event-loop/ecore/ecore-callback-manager.cpp
new file mode 100644 (file)
index 0000000..b6e5f3c
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "ecore-callback-manager.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+
+  /**
+   * Constructor
+   */
+  CallbackData( CallbackBase* callback )
+  :  mCallback(callback),
+     mRemoveFromContainerFunction(NULL),
+     mIdler(NULL)
+  {
+  }
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  CallbackBase*                   mCallback;      ///< call back
+  CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
+  Ecore_Idler*                    mIdler;         ///< ecore idler
+ };
+
+namespace
+{
+
+/**
+ * Called from the main thread while idle.
+ */
+Eina_Bool IdleCallback(void *data)
+{
+  CallbackData *callbackData = static_cast< CallbackData * >( data );
+
+  // remove callback data from the container
+  CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+  // run the function
+  CallbackBase::Execute( *callbackData->mCallback );
+
+  // delete our data
+  delete callbackData;
+
+  // CALLBACK Cancel will delete the idler so we don't need to call ecore_idler_del
+  return ECORE_CALLBACK_CANCEL;
+}
+
+} // unnamed namespace
+
+EcoreCallbackManager::EcoreCallbackManager()
+:mRunning(false)
+{
+}
+
+
+void EcoreCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG( mRunning == false );
+
+  mRunning = true;
+}
+
+void EcoreCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG( mRunning == true );
+
+  RemoveAllCallbacks();
+
+  mRunning = false;
+
+}
+
+bool EcoreCallbackManager::AddIdleCallback( CallbackBase* callback )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData *callbackData = new CallbackData( callback );
+
+  callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &EcoreCallbackManager::RemoveCallbackFromContainer );
+
+  // add the call back to the container
+  mCallbackContainer.push_front(callbackData);
+
+  // add the idler
+  callbackData->mIdler = ecore_idler_add( IdleCallback, callbackData);
+
+  DALI_ASSERT_ALWAYS( ( callbackData->mIdler != NULL ) && "Idle method not created" );
+
+  return true;
+}
+
+void EcoreCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
+{
+  mCallbackContainer.remove(callbackData);
+}
+
+void EcoreCallbackManager::RemoveAllCallbacks()
+{
+  // always called from main thread
+  for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
+  {
+    CallbackData* data = (*iter);
+
+    ecore_idler_del( data->mIdler );
+
+    delete data;
+
+  }
+  mCallbackContainer.clear();
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new EcoreCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/ecore/ecore-callback-manager.h b/adaptors/common/event-loop/ecore/ecore-callback-manager.h
new file mode 100644 (file)
index 0000000..f93cc72
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef __DALI_ECORE_CALLBACK_MANAGER_H__
+#define __DALI_ECORE_CALLBACK_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <list>
+
+// INTERNAL INCLUDES
+#include <callback-manager.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct CallbackData;
+
+/**
+ * Ecore interface to install call backs in the applications main loop.
+ */
+class EcoreCallbackManager : public CallbackManager
+{
+
+public:
+
+    /**
+     * @brief constructor
+     */
+    EcoreCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~EcoreCallbackManager()
+    {
+    }
+
+    /**
+     * @copydoc CallbackManager::AddCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+
+    /**
+     * @brief Remove all idle call backs that are pending
+     * Called by Stop()
+     * Always called from the main thread
+     */
+    void RemoveAllCallbacks();
+
+    /**
+     * @brief Removes a single call back from the container
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveCallbackFromContainer(CallbackData *callbackData);
+
+    /**
+     * @brief Remove a standard call back from ecore
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveStandardCallback(CallbackData *callbackData);
+
+
+    typedef std::list<CallbackData *>  CallbackList;
+
+    bool                           mRunning;            ///< flag is set to true if when running
+    CallbackList                   mCallbackContainer;  ///< container of live idle callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_ECORE_CALLBACK_MANAGER_H__
diff --git a/adaptors/common/event-loop/ecore/ecore-file-descriptor-monitor.cpp b/adaptors/common/event-loop/ecore/ecore-file-descriptor-monitor.cpp
new file mode 100644 (file)
index 0000000..edf139d
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "file-descriptor-monitor.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Using Impl to hide away EFL specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+  // Construction
+  Impl( int fileDescriptor, CallbackBase* callback )
+  : mFileDescriptor( fileDescriptor ),
+    mCallback( callback ),
+    mHandler( NULL )
+  {
+  }
+
+  ~Impl()
+  {
+    delete mCallback;
+  }
+
+  // Data
+  int mFileDescriptor;
+  CallbackBase* mCallback;
+  Ecore_Fd_Handler* mHandler;
+
+  // Static Methods
+
+  /**
+   * Called when the file descriptor receives an event.
+   */
+  static Eina_Bool EventDispatch(void* data, Ecore_Fd_Handler *handler)
+  {
+    Impl* impl = reinterpret_cast<Impl*>(data);
+
+    CallbackBase::Execute( *impl->mCallback );
+
+    return ECORE_CALLBACK_RENEW;
+  }
+};
+
+FileDescriptorMonitor::FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback )
+{
+  mImpl = new Impl(fileDescriptor, callback);
+
+  if (fileDescriptor >= 0)
+  {
+    mImpl->mHandler = ecore_main_fd_handler_add(fileDescriptor, ECORE_FD_READ, &Impl::EventDispatch, mImpl, NULL, NULL);
+  }
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  if (mImpl->mHandler)
+  {
+    ecore_main_fd_handler_del(mImpl->mHandler);
+  }
+
+  delete mImpl;
+  mImpl = NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/ecore/ecore-timer-impl.cpp b/adaptors/common/event-loop/ecore/ecore-timer-impl.cpp
new file mode 100644 (file)
index 0000000..5c3f479
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "timer-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// LOCAL STUFF
+namespace
+{
+Eina_Bool TimerSourceFunc (void *data)
+{
+  Timer* timer = static_cast<Timer*>(data);
+
+  bool keepRunning = timer->Tick();
+
+  return keepRunning ? EINA_TRUE : EINA_FALSE;
+}
+} // unnamed namespace
+
+/**
+ * Struct to hide away Ecore implementation details
+ */
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec )
+  : mId(NULL),
+    mInterval(milliSec)
+  {
+  }
+
+  Ecore_Timer * mId;
+  unsigned int mInterval;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  // stop timers
+  Stop();
+
+  delete mImpl;
+}
+
+void Timer::Start()
+{
+  if(mImpl->mId != NULL)
+  {
+    Stop();
+  }
+  mImpl->mId = ecore_timer_add( (double)mImpl->mInterval/1000.0f, (Ecore_Task_Cb)TimerSourceFunc, this );
+}
+
+void Timer::Stop()
+{
+  if (mImpl->mId != NULL)
+  {
+    ecore_timer_del(mImpl->mId);
+    mImpl->mId = NULL;
+  }
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  // stop existing timer
+  Stop();
+  mImpl->mInterval = interval;
+  // start new tick
+  Start();
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mId != NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp b/adaptors/common/event-loop/lib-uv/uv-callback-manager.cpp
new file mode 100644 (file)
index 0000000..ab8552d
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "uv-callback-manager.h"
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+static void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+}
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+  typedef void (*CallbackFunction)(uv_idle_t*);
+
+  /**
+   * Constructor
+   */
+  CallbackData( CallbackBase* callback )
+  :  mCallback(callback),
+     mRemoveFromContainerFunction(NULL),
+     mIdleHandle( NULL),
+     mExecute(true)
+  {
+  }
+
+  /**
+   * Add the idle callback
+   */
+  void AddIdle( CallbackFunction callback)
+  {
+    // heap allocate a handle as it will be alive after the CallbackData object is deleted.
+    mIdleHandle = new uv_idle_t;
+
+    // Node.JS uses uv_default_loop
+    uv_idle_init( uv_default_loop() , mIdleHandle );
+
+    mIdleHandle->data = this;
+
+    uv_idle_start( mIdleHandle, callback);
+  }
+
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    mIdleHandle->data = NULL;
+
+    uv_idle_stop( mIdleHandle );
+
+    uv_close( reinterpret_cast< uv_handle_t*>( mIdleHandle ) , FreeHandleCallback );
+
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  // Data
+  CallbackBase*                   mCallback;      ///< call back
+  CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
+  uv_idle_t*                      mIdleHandle;   ///< idle handle
+  bool                            mExecute;      ///< whether to run the callback
+
+};
+
+namespace
+{
+void IdleCallback( uv_idle_t* handle )
+{
+  CallbackData *callbackData = static_cast<CallbackData *>(handle->data);
+
+  // remove callback data from the container first in case our callback tries to modify the container
+  CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+  // run the function
+  CallbackBase::Execute( *callbackData->mCallback );
+
+  // will clear up the handle
+  delete callbackData;
+
+}
+}
+
+UvCallbackManager::UvCallbackManager()
+:mRunning(false)
+{
+}
+
+void UvCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG( mRunning == false );
+  mRunning = true;
+}
+
+void UvCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG( mRunning == true );
+
+  mRunning = false;
+
+  for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
+  {
+    CallbackData* data = (*iter);
+
+    delete data;
+  }
+  mCallbackContainer.clear();
+}
+
+bool UvCallbackManager::AddIdleCallback( CallbackBase* callback )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData *callbackData = new CallbackData(callback );
+
+  // To inform the manager a callback has finished, we get it to call RemoveCallbackFromContainer
+  callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &UvCallbackManager::RemoveCallbackFromContainer );
+
+  // add the call back to the container
+  mCallbackContainer.push_front(callbackData);
+
+  // init the callback
+  callbackData->AddIdle( &IdleCallback );
+
+  return true;
+}
+
+void UvCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
+{
+  mCallbackContainer.remove(callbackData);
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new UvCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/lib-uv/uv-callback-manager.h b/adaptors/common/event-loop/lib-uv/uv-callback-manager.h
new file mode 100644 (file)
index 0000000..78abab6
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef __DALI_UV_CALLBACK_MANAGER_H__
+#define __DALI_UV_CALLBACK_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <list>
+
+// INTERNAL INCLUDES
+#include <callback-manager.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct CallbackData;
+
+/**
+ * @brief LibUV callback manager used to install call backs in the applications main loop.
+ * The manager keeps track of all callbacks, so that if Stop() is called it can remove them.
+ */
+class UvCallbackManager : public CallbackManager
+{
+
+public:
+
+     /**
+     * @brief constructor
+     */
+    UvCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~UvCallbackManager(){}
+
+    /**
+     * @copydoc CallbackManager::AddCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+
+    /**
+     * @brief Removes a single call back from the container
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveCallbackFromContainer(CallbackData *callbackData);
+
+
+    typedef std::list<CallbackData *>  CallbackList;    ///< list of callbacks installed
+
+    bool                           mRunning;            ///< flag is set to true if when running
+    CallbackList                   mCallbackContainer;  ///< container of live callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_UV_CALLBACK_MANAGER_H__
diff --git a/adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp b/adaptors/common/event-loop/lib-uv/uv-file-descriptor-monitor.cpp
new file mode 100644 (file)
index 0000000..0ce27cb
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "file-descriptor-monitor.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <uv.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+}
+
+/**
+ * Using Impl to hide away UV specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+public:
+
+  // Constructor
+  Impl( int fileDescriptor, CallbackBase* callback )
+  : mFileDescriptor( fileDescriptor ),
+    mCallback( callback ),
+    pollHandle( NULL )
+  {
+
+    // heap allocate a handle as it will be alive after the FileDescriptorMonitor::Impl object is deleted.
+    pollHandle = new uv_poll_t;
+
+    // Node.JS uses uv_default_loop
+    uv_poll_init( uv_default_loop(), pollHandle, fileDescriptor);
+
+    pollHandle->data = this;
+
+    uv_poll_start( pollHandle, UV_READABLE, PollCabllack);
+  }
+
+  ~Impl()
+  {
+    uv_poll_stop( pollHandle );
+
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    pollHandle->data = NULL;
+
+    uv_close(reinterpret_cast<uv_handle_t*> ( pollHandle ) , FreeHandleCallback );
+
+    delete mCallback;
+  }
+
+  static void PollCabllack(uv_poll_t* handle, int status, int events)
+  {
+     if( handle->data )
+     {
+        FileDescriptorMonitor::Impl* impl= static_cast<FileDescriptorMonitor::Impl* >(handle->data);
+        // run the function
+        CallbackBase::Execute( *impl->mCallback );
+     }
+  }
+  // Data
+  int mFileDescriptor;
+  CallbackBase* mCallback;
+  uv_poll_t* pollHandle;
+
+};
+
+
+FileDescriptorMonitor::FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback )
+{
+  if (fileDescriptor < 0)
+  {
+    return;
+  }
+
+  // waiting for a write event on a file descriptor
+  mImpl = new Impl(fileDescriptor, callback);
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  delete mImpl;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp b/adaptors/common/event-loop/lib-uv/uv-timer-impl.cpp
new file mode 100644 (file)
index 0000000..01ec2f4
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "timer-impl.h"
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+void TimerSourceFunc (uv_timer_t* handle)
+{
+  Timer* timer = static_cast<Timer*>(handle->data);
+
+  bool keepRunning = timer->Tick();
+  if( !keepRunning )
+  {
+    timer->Stop();
+  }
+}
+void FreeHandleCallback(uv_handle_t* handle )
+{
+  delete handle;
+}
+
+} // unnamed namespace
+
+/**
+ * Struct to hide away Ecore implementation details
+ */
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec )
+  : mTimerHandle( NULL ),
+    mInterval( milliSec ),
+    mRunning( false )
+  {
+  }
+
+  ~Impl()
+  {
+    // the handle will still be alive for a short period after calling uv_close
+    // set the data to NULL to avoid a dangling pointer
+    mTimerHandle->data = NULL;
+
+    uv_close( reinterpret_cast< uv_handle_t* >( mTimerHandle ), FreeHandleCallback );
+  }
+
+  bool Running()
+  {
+    return mRunning;
+  }
+
+  void Start( void* internalTimerPtr )
+  {
+    Stop(); // make sure we stop first if its currently running
+
+    if( !mTimerHandle )
+    {
+      // heap allocate the handle as its lifetime will be longer than TimerImpl
+      mTimerHandle = new uv_timer_t;
+
+      // initialize the handle
+      uv_timer_init( uv_default_loop(), mTimerHandle);
+    }
+
+    mRunning = true;
+
+    mTimerHandle->data = internalTimerPtr;
+
+    uv_timer_start( mTimerHandle, TimerSourceFunc, mInterval, mInterval);
+  }
+
+  void Stop()
+  {
+    if( mRunning )
+    {
+      mTimerHandle->data = NULL;
+      uv_timer_stop( mTimerHandle );
+      mRunning = false;
+    }
+  }
+
+  uv_timer_t* mTimerHandle;
+  unsigned int mInterval;
+  bool      mRunning;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  DALI_LOG_ERROR(" new timer");
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  // stop timers
+  Stop();
+
+  delete mImpl;
+}
+
+void Timer::Start()
+{
+  mImpl->Start( this );
+}
+
+void Timer::Stop()
+{
+  mImpl->Stop();
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  // stop existing timer
+  Stop();
+
+  mImpl->mInterval = interval;
+
+  // start new tick
+  Start();
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mRunning;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/event-handler.h b/adaptors/common/events/event-handler.h
new file mode 100644 (file)
index 0000000..ad6e998
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef __DALI_INTERNAL_EVENT_HANDLER_H__
+#define __DALI_INTERNAL_EVENT_HANDLER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/events/touch-event-combiner.h>
+#include <style-monitor.h>
+
+// INTERNAL INCLUDES
+#include <damage-observer.h>
+#include <drag-and-drop-detector-impl.h>
+#include <accessibility-adaptor-impl.h>
+#include <clipboard-event-notifier-impl.h>
+#include <imf-manager-impl.h>
+#include <rotation-observer.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CoreEventInterface;
+class GestureManager;
+class StyleMonitor;
+
+/**
+ * The Event Handler class is responsible for setting up receiving of Ecore events and then converts them
+ * to TouchEvents when it does receive them.
+ *
+ * These TouchEvents are then passed on to Core.
+ */
+class EventHandler
+{
+public:
+
+  /**
+   * Constructor.
+   * @param[in]  surface                  The surface where events will be sent to.
+   * @param[in]  coreEventInterface       Used to send events to Core.
+   * @param[in]  gestureManager           The Gesture Manager.
+   * @param[in]  damageObserver           The damage observer (to pass damage events to).
+   * @param[in]  dndDetector              The Drag & Drop listener (to pass DnD events to).
+   */
+  EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector );
+
+  /**
+   * Destructor.
+   */
+  ~EventHandler();
+
+  /**
+   * Feed (Send) touch event to core and gesture manager
+   * @param[in] touchEvent  The touch event holding the touch point information.
+   */
+  void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+  /**
+   * Feed (Send) wheel event to core and gesture manager
+   * @param[in]  wheelEvent The wheel event
+   */
+  void FeedWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * Feed (Send) key event to core
+   * @param[in] keyEvent The key event holding the key information.
+   */
+  void FeedKeyEvent( KeyEvent& keyEvent );
+
+  /**
+   * Feed (Send) an event to core
+   * @param[in] event  The event information.
+   */
+  void FeedEvent( Integration::Event& event );
+
+  /**
+   * Called when the adaptor is paused.
+   */
+  void Pause();
+
+  /**
+   * Called when the adaptor is resumed (from pause).
+   */
+  void Resume();
+
+  /**
+   * Sets the Drag & Drop detector.
+   * @param[in]  detector  An intrusive pointer to the Drag & Drop listener to set. To unset pass in NULL.
+   */
+  void SetDragAndDropDetector( DragAndDropDetectorPtr detector );
+
+  /**
+   * Set the rotation observer (note, some adaptors may not have a rotation observer)
+   * @param[in] observer The rotation observer
+   */
+  void SetRotationObserver( RotationObserver* observer );
+
+private:
+
+  /**
+   * Send touch event to core.
+   * @param[in]  point      The touch point information.
+   * @param[in]  timeStamp  The time the touch occurred.
+   */
+  void SendEvent(TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * Send key event to core.
+   * @param[in]  keyEvent The KeyEvent to send.
+   */
+  void SendEvent(KeyEvent& keyEvent);
+
+  /**
+   * Send wheel event to core.
+   * @param[in]  wheelEvent The wheel event
+   */
+  void SendWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * Send a style change event to the style monitor.
+   * @param[in]  styleChange  The style that has changed.
+   */
+  void SendEvent( StyleChange::Type styleChange );
+
+  /**
+   * Send a window damage event to the observer.
+   * @param[in]  area  Damaged area.
+   */
+  void SendEvent( const DamageArea& area );
+
+  /**
+   * Inform rotation observer of rotation prepare event
+   * @param[in] rotation The rotation event
+   */
+  void SendRotationPrepareEvent( const RotationEvent& rotation );
+
+  /**
+   * Inform rotation observer of rotation prepare event
+   */
+  void SendRotationRequestEvent();
+
+  /**
+   * Resets the event handler.
+   * Called when the adaptor is paused or resumed.
+   */
+  void Reset();
+
+private:
+
+  // Undefined
+  EventHandler( const EventHandler& eventHandler );
+
+  // Undefined
+  EventHandler& operator=( const EventHandler& eventHandler );
+
+private:
+
+  CoreEventInterface& mCoreEventInterface; ///< Used to send events to Core.
+  Dali::Integration::TouchEventCombiner mCombiner; ///< Combines multi-touch events.
+  GestureManager& mGestureManager; ///< Reference to the GestureManager, set on construction, to send touch events to for analysis.
+  Dali::StyleMonitor mStyleMonitor; ///< Handle to the style monitor, set on construction, to send font size and font change events to.
+  DamageObserver& mDamageObserver; ///< Reference to the DamageObserver, set on construction, to sent damage events to.
+  RotationObserver* mRotationObserver; ///< Pointer to rotation observer, if present.
+
+  DragAndDropDetectorPtr mDragAndDropDetector; ///< Pointer to the drag & drop detector, to send Drag & Drop events to.
+  Dali::AccessibilityAdaptor mAccessibilityAdaptor; ///< Pointer to the accessibility adaptor
+  Dali::ClipboardEventNotifier mClipboardEventNotifier; ///< Pointer to the clipboard event notifier
+  Dali::Clipboard mClipboard;///< Pointer to the clipboard
+
+  struct Impl; ///< Contains Ecore specific information
+  Impl* mImpl; ///< Created on construction and destroyed on destruction.
+
+  bool mPaused; ///< The paused state of the adaptor.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_EVENT_HANDLER_H__
diff --git a/adaptors/common/events/gesture-detector.h b/adaptors/common/events/gesture-detector.h
new file mode 100644 (file)
index 0000000..d7ccf67
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef __DALI_INTERNAL_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/gesture.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/object/ref-object.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+class GestureRequest;
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract Base class for all adaptor gesture detectors.
+ *
+ * @note this may be replaced by gesture events sent directly from X.
+ */
+class GestureDetector : public RefObject
+{
+public:
+
+  /**
+   * Called by the gesture manager when it gets a touch event.  The gesture detector should
+   * evaluate this event along with previously received events to determine whether the gesture
+   * they require has taken place.
+   * @param[in]  event  The latest touch event.
+   */
+  virtual void SendEvent(const Integration::TouchEvent& event) = 0;
+
+  /**
+   * Called by the gesture manager when Core updates the gesture's detection requirements.
+   * @param[in]  request  The updated detection requirements.
+   */
+  virtual void Update(const Integration::GestureRequest& request) = 0;
+
+  /**
+   * Returns the type of gesture detector.
+   * @return Type of gesture detector.
+   */
+  Gesture::Type GetType() const { return mType; }
+
+protected:
+
+  /**
+   * Protected Constructor.  Should only be able to create derived class objects.
+   * @param[in]  screenSize    The size of the screen.
+   * @param[in]  detectorType  The type of gesture detector.
+   */
+  GestureDetector(Vector2 screenSize, Gesture::Type detectorType)
+  : mScreenSize(screenSize), mType(detectorType) {}
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~GestureDetector() {}
+
+protected:
+
+  Vector2 mScreenSize;
+  Gesture::Type mType;
+};
+
+typedef IntrusivePtr<GestureDetector> GestureDetectorPtr;
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/events/gesture-manager.cpp b/adaptors/common/events/gesture-manager.cpp
new file mode 100644 (file)
index 0000000..8ecac2e
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "gesture-manager.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+#include <events/long-press-gesture-detector.h>
+#include <events/pan-gesture-detector.h>
+#include <events/pinch-gesture-detector.h>
+#include <events/tap-gesture-detector.h>
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gLogFilter  = Integration::Log::Filter::New( Debug::NoLogging, false, "LOG_GESTURE_MANAGER" );
+
+/**
+ * Helper method to return the string representation of a gesture type.
+ */
+const char * GetGestureTypeString( Gesture::Type type )
+{
+  static const char * const pinch( "Pinch" );
+  static const char * const pan( "Pan" );
+  static const char * const tap( "tap" );
+  static const char * const longPress( "LongPress" );
+  static const char * const invalid( "Invalid" );
+
+  const char * retVal( NULL );
+
+  switch ( type )
+  {
+    case Gesture::LongPress:
+    {
+      retVal = longPress;
+      break;
+    }
+
+    case Gesture::Pan:
+    {
+      retVal = pan;
+      break;
+    }
+
+    case Gesture::Pinch:
+    {
+      retVal = pinch;
+      break;
+    }
+
+    case Gesture::Tap:
+    {
+      retVal = tap;
+      break;
+    }
+
+    default:
+      retVal = invalid;
+      break;
+  }
+
+  return retVal;
+};
+#endif // DEBUG_ENABLED
+
+const float MINIMUM_DISTANCE_DELTA_DIVISOR = 85.0f;
+} // unnamed namespace
+
+GestureManager::GestureManager(CoreEventInterface& coreEventInterface, Vector2 screenSize,CallbackManager* callbackManager, EnvironmentOptions& environmentOptions)
+: mCoreEventInterface( coreEventInterface ),
+  mScreenSize( screenSize ),
+  mCallbackManager( callbackManager ),
+  mEnvironmentOptions( environmentOptions ),
+  mMinimumDistanceDelta(-1.0f),
+  mRunning( true ) // This allows gestures to be created before Adaptor::Start() is called e.g. by Indicator
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Creating GestureManager\n" );
+}
+
+GestureManager::~GestureManager()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Destroying GestureManager\n" );
+}
+
+void GestureManager::SendEvent(const Integration::TouchEvent& event)
+{
+  if (mRunning)
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SendEvent: START\n" );
+
+    // gestures can be added / deleted during SendEvent so we make a copy of the container.
+    // the gestures are reference counted, so unused gesture detectors will be deleted when
+    // the local variable detectors goes out of scope.
+    GestureDetectorContainer detectors( mGestureDetectors );
+
+    // Send the event to all gesture detectors.
+    for ( GestureDetectorContainer::iterator iter = detectors.begin(), endIter = detectors.end(); iter != endIter; ++iter )
+    {
+      (*iter)->SendEvent(event);
+    }
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "SendEvent: END\n" );
+  }
+}
+
+void GestureManager::Stop()
+{
+  if (mRunning)
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Stop\n" );
+
+    mGestureDetectors.clear();
+    mRunning = false;
+  }
+}
+
+void GestureManager::SetMinimumPinchDistance(float distance)
+{
+  mMinimumDistanceDelta = distance;
+  for( GestureDetectorContainer::iterator iter = mGestureDetectors.begin(), endIter = mGestureDetectors.end(); iter != endIter; ++iter )
+  {
+    if ( ( *iter )->GetType() == Gesture::Pinch )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Set Minimum Pinch Distance: %f\n", distance );
+      PinchGestureDetector* gestureDetector = static_cast<PinchGestureDetector*>(iter->Get());
+      gestureDetector->SetMinimumPinchDistance(distance);
+      break;
+    }
+  }
+}
+
+void GestureManager::Register(const Integration::GestureRequest& request)
+{
+  if (mRunning)
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "Creating %s Detector\n", GetGestureTypeString( request.type ) );
+
+    switch (request.type)
+    {
+      case Gesture::LongPress:
+      {
+        GestureDetectorPtr gesture = new LongPressGestureDetector(mCoreEventInterface, mScreenSize, static_cast<const Integration::LongPressGestureRequest&>(request));
+        mGestureDetectors.push_back(gesture);
+        break;
+      }
+
+      case Gesture::Pan:
+      {
+        GestureDetectorPtr gesture = new PanGestureDetector(mCoreEventInterface, mScreenSize, static_cast<const Integration::PanGestureRequest&>(request), mEnvironmentOptions);
+        mGestureDetectors.push_back(gesture);
+        break;
+      }
+
+      case Gesture::Pinch:
+      {
+        float minPinchDistance = mMinimumDistanceDelta >= 0.0f ? mMinimumDistanceDelta : (mScreenSize.height / MINIMUM_DISTANCE_DELTA_DIVISOR);
+        GestureDetectorPtr gesture = new PinchGestureDetector(mCoreEventInterface, mScreenSize, minPinchDistance);
+        mGestureDetectors.push_back(gesture);
+        break;
+      }
+
+      case Gesture::Tap:
+      {
+        GestureDetectorPtr gesture = new TapGestureDetector(mCoreEventInterface, mScreenSize, static_cast<const Integration::TapGestureRequest&>(request));
+        mGestureDetectors.push_back(gesture);
+        break;
+      }
+
+      default:
+        DALI_ASSERT_DEBUG(false);
+        break;
+    }
+  }
+}
+
+void GestureManager::Unregister(const Integration::GestureRequest& request)
+{
+  if ( mRunning )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "Unregister: %s\n", GetGestureTypeString( request.type ) );
+
+    DeleteGestureDetector( request.type );
+
+  }
+}
+
+void GestureManager::Update(const Integration::GestureRequest& request)
+{
+  for( GestureDetectorContainer::iterator iter = mGestureDetectors.begin(), endIter = mGestureDetectors.end(); iter < endIter; ++iter )
+  {
+    if ( (*iter)->GetType() == request.type )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Update: %s\n", GetGestureTypeString( request.type ) );
+      (*iter)->Update( request );
+      break;
+    }
+  }
+}
+
+void GestureManager::DeleteGestureDetector( Gesture::Type type )
+{
+  for( GestureDetectorContainer::iterator iter = mGestureDetectors.begin(), endIter = mGestureDetectors.end(); iter != endIter; ++iter )
+  {
+    if ( ( *iter )->GetType() == type )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "DeleteGestureDetector: %s\n", GetGestureTypeString( type ) );
+      mGestureDetectors.erase( iter );
+      break;
+    }
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/gesture-manager.h b/adaptors/common/events/gesture-manager.h
new file mode 100644 (file)
index 0000000..f062683
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef __DALI_INTERNAL_GESTURE_MANAGER_H__
+#define __DALI_INTERNAL_GESTURE_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/integration-api/gesture-manager.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CallbackManager;
+class CoreEventInterface;
+class EnvironmentOptions;
+
+/**
+ * Implementation of the Integration::GestureManager.
+ *
+ * Contains a list of adaptor gesture detectors. It passes touch events to each required detector which
+ * in turn process them to determine if their corresponding gesture has occurred.
+ */
+class GestureManager : public Integration::GestureManager
+{
+public:
+
+  /**
+   * Constructor.
+   * @param[in] coreEventInterface Used to send events to Core.
+   * @param[in] screenSize The size of the screen.
+   * @param[in] callbackManager used to install callbacks
+   * @param[in] environmentOptions Environment Options
+   */
+  GestureManager(CoreEventInterface& coreEventInterface, Vector2 screenSize, CallbackManager* callbackManager, EnvironmentOptions& environmentOptions);
+
+  /**
+   * The destructor
+   */
+  virtual ~GestureManager();
+
+public:
+
+  /**
+   * Used by the event handler to send touch events to the Gesture Manager.
+   * @param[in]  event  The latest touch event.
+   */
+  void SendEvent(const Integration::TouchEvent& event);
+
+  /**
+   * Used by the event handler to stop the GestureManager detection.
+   */
+  void Stop();
+
+  /**
+   * @brief Sets minimum distance in pixels that the fingers must move towards/away from each other in order to
+   * trigger a pinch gesture
+   *
+   * @param[in] distance The minimum pinch distance in pixels
+   */
+  void SetMinimumPinchDistance(float distance);
+
+public: // GestureManager overrides
+
+  /**
+   * copydoc Dali::Integration::GestureManager::Register(const Integration::GestureRequest&)
+   */
+  virtual void Register(const Integration::GestureRequest& request);
+
+  /**
+   * copydoc Dali::Integration::GestureManager::Unregister(const Integration::GestureRequest&)
+   */
+  virtual void Unregister(const Integration::GestureRequest& request);
+
+  /**
+   * copydoc Dali::Integration::GestureManager::Unregister(const Integration::GestureRequest&)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+private:
+
+  /**
+   * Used to delete the gesture detector of the given type.
+   */
+  void DeleteGestureDetector( Gesture::Type type );
+
+private:
+
+  typedef std::vector<GestureDetectorPtr> GestureDetectorContainer;
+
+  CoreEventInterface& mCoreEventInterface;
+  GestureDetectorContainer mGestureDetectors;
+  Vector2 mScreenSize;
+  CallbackManager* mCallbackManager;
+  EnvironmentOptions& mEnvironmentOptions;
+  float mMinimumDistanceDelta; ///< The minimum distance before a pinch is applicable. (-1.0f means pinch detector uses default value)
+  bool mRunning; ///< States whether the GestureManager is running or not.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_GESTURE_MANAGER_H__
diff --git a/adaptors/common/events/long-press-gesture-detector.cpp b/adaptors/common/events/long-press-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..5c35825
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "long-press-gesture-detector.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/integration-api/events/gesture-requests.h>
+#include <dali/integration-api/events/long-press-gesture-event.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+#include <system-settings.h>
+
+// INTERNAL INCLUDES
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// TODO: Set these according to DPI
+const float MAXIMUM_MOTION_ALLOWED = 60.0f;
+// TODO: Set this time according to system setting (vconf)
+const unsigned long LONG_PRESS_TIME = 500u;
+} // unnamed namespace
+
+LongPressGestureDetector::LongPressGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::LongPressGestureRequest& request)
+: GestureDetector(screenSize, Gesture::LongPress),
+  mCoreEventInterface(coreEventInterface),
+  mState(Clear),
+  mMinimumTouchesRequired(request.minTouches),
+  mMaximumTouchesRequired(request.maxTouches),
+  mTouchTime(0),
+  mTimerSlot( this )
+{
+  mTimer = Dali::Timer::New(GetSystemValue());
+  mTimer.TickSignal().Connect( mTimerSlot, &LongPressGestureDetector::TimerCallback );
+}
+
+LongPressGestureDetector::~LongPressGestureDetector()
+{
+}
+
+void LongPressGestureDetector::SendEvent(const Integration::TouchEvent& event)
+{
+  unsigned int pointCount( event.GetPointCount() );
+
+  switch (mState)
+  {
+    // Clear: Wait till one point touches the screen before starting timer.
+    case Clear:
+    {
+      const TouchPoint& point = event.points[0];
+
+      if ( point.state == TouchPoint::Down )
+      {
+        mTouchPositions.clear();
+        mTouchPositions[point.deviceId] = point.screen;
+
+        mTouchTime = event.time;
+
+        mTimer.SetInterval(GetSystemValue());
+        mTimer.Start();
+
+        // A long press gesture may be possible, tell Core about this and change state to Touched.
+        mState = Touched;
+        EmitGesture( Gesture::Possible );
+      }
+
+      break;
+    }
+
+    // Touched: Monitor movement and addition/removal of points.
+    case Touched:
+    {
+      if (pointCount > mMaximumTouchesRequired)
+      {
+        // A long press did not occur, tell Core that it was cancelled and change state to Failed.
+        EmitGesture( Gesture::Cancelled );
+        mTouchPositions.clear();
+        mTimer.Stop();
+        mState = Failed;
+        break;
+      }
+
+      bool endLoop(false);
+
+      for (std::vector<TouchPoint>::const_iterator iter = event.points.begin(), endIter = event.points.end();
+           iter != endIter && !endLoop; ++iter)
+      {
+        switch( iter->state )
+        {
+          // add point.
+          case TouchPoint::Down:
+          {
+            mTouchPositions[iter->deviceId] = iter->screen;
+            break;
+          }
+
+          // remove point.
+          case TouchPoint::Up:
+          case TouchPoint::Interrupted:
+          {
+            // System has interrupted us, long press is not possible, inform Core
+            EmitGesture( Gesture::Cancelled );
+            mTouchPositions.clear();
+            mTimer.Stop();
+            mState = ( pointCount == 1 ) ? Clear : Failed; // Change state to Clear if only one point, Failed otherwise.
+            endLoop = true;
+            break;
+          }
+
+          case TouchPoint::Motion:
+          {
+            const Vector2 touchPosition( mTouchPositions[iter->deviceId] - iter->screen );
+            float distanceSquared = touchPosition.LengthSquared();
+
+            if (distanceSquared > ( MAXIMUM_MOTION_ALLOWED * MAXIMUM_MOTION_ALLOWED ) )
+            {
+              // We have moved more than the allowable motion for a long press gesture. Inform Core and change state to Failed.
+              EmitGesture( Gesture::Cancelled );
+              mTimer.Stop();
+              mState = Failed;
+              endLoop = true;
+            }
+            break;
+          }
+
+          case TouchPoint::Stationary:
+          case TouchPoint::Leave:
+          case TouchPoint::Last:
+          {
+            break;
+          }
+        }
+      }
+      break;
+    }
+
+    // Failed/Finished: Monitor the touches, waiting for all touches to be released.
+    case Failed:
+    case Finished:
+    {
+      // eventually the final touch point will be removed, marking the end of this gesture.
+      if ( pointCount == 1 )
+      {
+        TouchPoint::State primaryPointState = event.points[0].state;
+
+        if ( (primaryPointState == TouchPoint::Up) || (primaryPointState == TouchPoint::Interrupted) )
+        {
+          if(mState == Finished)
+          {
+            // When the last touch point is lifted, we should inform the Core that the Long press has finished.
+            EmitGesture(Gesture::Finished);
+          }
+          mTouchPositions.clear();
+          mState = Clear; // Reset state to clear when last touch point is lifted.
+        }
+      }
+      break;
+    }
+  }
+}
+
+void LongPressGestureDetector::Update(const Integration::GestureRequest& request)
+{
+  const Integration::LongPressGestureRequest& longPress = static_cast<const Integration::LongPressGestureRequest&>(request);
+
+  mMinimumTouchesRequired = longPress.minTouches;
+  mMaximumTouchesRequired = longPress.maxTouches;
+}
+
+bool LongPressGestureDetector::TimerCallback()
+{
+  EmitGesture(Gesture::Started);
+
+  mState = Finished;
+
+  // There is no touch event at this time, so ProcessEvents must be called directly
+  mCoreEventInterface.ProcessCoreEvents();
+
+  return false;
+}
+
+void LongPressGestureDetector::EmitGesture(Gesture::State state)
+{
+  unsigned int touchPoints ( mTouchPositions.size() );
+
+  // We should tell Core about the Possible and Cancelled states regardless of whether we have satisfied long press requirements.
+  if ( (state == Gesture::Possible) ||
+       (state == Gesture::Cancelled) ||
+       (touchPoints >= mMinimumTouchesRequired) )
+  {
+    Integration::LongPressGestureEvent longPress( state );
+    longPress.numberOfTouches = touchPoints;
+
+    for (std::map<int, Vector2>::iterator iter = mTouchPositions.begin(), endIter = mTouchPositions.end();
+         iter != endIter; ++iter)
+    {
+      longPress.point += iter->second;
+    }
+    longPress.point /= touchPoints;
+
+    longPress.time = mTouchTime;
+    if ( state != Gesture::Possible )
+    {
+      longPress.time += GetSystemValue();
+    }
+
+    mCoreEventInterface.QueueCoreEvent(longPress);
+  }
+}
+
+int LongPressGestureDetector::GetSystemValue()
+{
+  return GetLongPressTime( LONG_PRESS_TIME );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/long-press-gesture-detector.h b/adaptors/common/events/long-press-gesture-detector.h
new file mode 100644 (file)
index 0000000..7d7327a
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef __DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <map>
+#include <timer.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+struct LongPressGestureRequest;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CoreEventInterface;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a long press gesture has taken place.
+ * Emits a LongPressGestureEvent (state = Started) when a long press has been detected (Touch held down for more than duration).
+ * Emits a further LongPressGestureEvent (state = Finished) when a long press has been completed (Touch Release).
+ */
+class LongPressGestureDetector : public GestureDetector
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in] coreEventInterface Used to send events to Core.
+   * @param[in] screenSize  The size of the screen.
+   * @param[in] request     The long press gesture request.
+   */
+  LongPressGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::LongPressGestureRequest& request);
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~LongPressGestureDetector();
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+   */
+  virtual void SendEvent(const Integration::TouchEvent& event);
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+private:
+
+  /**
+   * Timer Callback
+   * @return will return false; one-shot timer.
+   */
+  bool TimerCallback();
+
+  /**
+   * Emits the long press gesture if all conditions are applicable.
+   * @param[in] state The state of this gesture event.
+   */
+  void EmitGesture(Gesture::State state);
+
+  /**
+   * Get current system setting value for tap and hold gesture
+   * @return system value for tap and hold gesture [ms]
+   */
+  int GetSystemValue();
+
+private:
+
+  /**
+   * Internal state machine.
+   */
+  enum State
+  {
+    Clear,      ///< No gesture detected.
+    Touched,    ///< User is touching the screen.
+    Failed,     ///< Gesture has failed.
+    Finished    ///< Gesture has been detected and sent.
+  };
+
+  CoreEventInterface& mCoreEventInterface; ///< Used to send events to Core.
+  State mState; ///< The current state of the detector.
+
+  unsigned int mMinimumTouchesRequired;   ///< The minimum touches required before emitting a long press.
+  unsigned int mMaximumTouchesRequired;   ///< The maximum touches allowable. Any more and a long press is not emitted.
+
+  std::map<int, Vector2> mTouchPositions; ///< A map with all the touch down positions.
+  unsigned long mTouchTime;               ///< The time we first pressed down.
+
+  Dali::Timer mTimer;                     ///< The timer used to determine a long press.
+  SlotDelegate< LongPressGestureDetector > mTimerSlot;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_LONG_PRESS_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/events/pan-gesture-detector-base.cpp b/adaptors/common/events/pan-gesture-detector-base.cpp
new file mode 100644 (file)
index 0000000..9c27caf
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "pan-gesture-detector-base.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+
+#include <dali/integration-api/events/gesture-requests.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <base/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f );
+const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN );
+const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f );
+const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 );
+const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 );
+const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2);
+} // unnamed namespace
+
+PanGestureDetectorBase::PanGestureDetectorBase(Vector2 screenSize, const Integration::PanGestureRequest& request, EnvironmentOptions* environmentOptions)
+: GestureDetector( screenSize, Gesture::Pan ),
+  mState( Clear ),
+  mThresholdAdjustmentsRemaining( 0 ),
+  mThresholdTotalAdjustments( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ),
+  mPrimaryTouchDownTime( 0 ),
+  mMinimumTouchesRequired( request.minTouches ),
+  mMaximumTouchesRequired( request.maxTouches ),
+  mMinimumDistanceSquared( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ),
+  mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ),
+  mMotionEvents( 0 )
+{
+  if ( environmentOptions )
+  {
+    int minimumDistance = environmentOptions->GetMinimumPanDistance();
+    if ( minimumDistance >= 0 )
+    {
+      mMinimumDistanceSquared = minimumDistance * minimumDistance;
+
+      // Usually, we do not want to apply the threshold straight away, but phased over the first few pans
+      // Set our distance to threshold adjustments ratio here.
+      mThresholdTotalAdjustments = minimumDistance * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO;
+    }
+
+    int minimumEvents = environmentOptions->GetMinimumPanEvents();
+    if ( minimumEvents >= 1 )
+    {
+      mMinimumMotionEvents = minimumEvents - 1; // Down is the first event
+    }
+  }
+}
+
+PanGestureDetectorBase::~PanGestureDetectorBase()
+{
+}
+
+void PanGestureDetectorBase::SendEvent(const Integration::TouchEvent& event)
+{
+  TouchPoint::State primaryPointState(event.points[0].state);
+
+  if (primaryPointState == TouchPoint::Interrupted)
+  {
+    if ( ( mState == Started ) || ( mState == Possible ) )
+    {
+      // If our pan had started and we are interrupted, then tell Core that pan is cancelled.
+      mTouchEvents.push_back(event);
+      SendPan(Gesture::Cancelled, event);
+    }
+    mState = Clear; // We should change our state to Clear.
+    mTouchEvents.clear();
+  }
+  else
+  {
+    switch (mState)
+    {
+      case Clear:
+      {
+        if (primaryPointState == TouchPoint::Down)
+        {
+          mPrimaryTouchDownLocation = event.points[0].screen;
+          mPrimaryTouchDownTime = event.time;
+          mMotionEvents = 0;
+          if (event.GetPointCount() == mMinimumTouchesRequired)
+          {
+            // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly.
+            mState = Possible;
+            SendPan(Gesture::Possible, event);
+          }
+
+          mTouchEvents.push_back(event);
+        }
+        break;
+      }
+
+      case Possible:
+      {
+        unsigned int pointCount(event.GetPointCount());
+        if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+        {
+          if (primaryPointState == TouchPoint::Motion)
+          {
+            mTouchEvents.push_back(event);
+            mMotionEvents++;
+
+            Vector2 delta(event.points[0].screen - mPrimaryTouchDownLocation);
+
+            if ( ( mMotionEvents >= mMinimumMotionEvents ) &&
+                 ( delta.LengthSquared() >= mMinimumDistanceSquared ) )
+            {
+              // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly.
+              mState = Started;
+              SendPan(Gesture::Started, event);
+            }
+          }
+          else if (primaryPointState == TouchPoint::Up)
+          {
+            Vector2 delta(event.points[0].screen - mPrimaryTouchDownLocation);
+            if(delta.LengthSquared() >= mMinimumDistanceSquared)
+            {
+              SendPan(Gesture::Started, event);
+              mTouchEvents.push_back(event);
+              SendPan(Gesture::Finished, event);
+            }
+            else
+            {
+              // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear.
+              SendPan(Gesture::Cancelled, event);
+            }
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+        }
+        else
+        {
+          // We do not satisfy pan conditions, tell Core our Gesture has been cancelled.
+          SendPan(Gesture::Cancelled, event);
+
+          if (pointCount == 1 && primaryPointState == TouchPoint::Up)
+          {
+            // If we have lifted the primary touch point, then change our state to Clear...
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+          else
+          {
+            // ...otherwise change it to Failed.
+            mState = Failed;
+          }
+        }
+        break;
+      }
+
+      case Started:
+      {
+        mTouchEvents.push_back(event);
+
+        unsigned int pointCount(event.GetPointCount());
+        if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+        {
+          switch (primaryPointState)
+          {
+            case TouchPoint::Motion:
+              // Pan is continuing, tell Core.
+              SendPan(Gesture::Continuing, event);
+              break;
+
+            case TouchPoint::Up:
+              // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear.
+              SendPan(Gesture::Finished, event);
+              mState = Clear;
+              mTouchEvents.clear();
+              break;
+
+            case TouchPoint::Stationary:
+              if (pointCount == mMinimumTouchesRequired)
+              {
+                std::vector<TouchPoint>::const_iterator iter = event.points.begin() + 1; // We already know the state of the first point
+                for(; iter != event.points.end(); ++iter)
+                {
+                  if(iter->state == TouchPoint::Up)
+                  {
+                    // The number of touch points will be less than the minimum required.  Inform core and change our state to Finished.
+                    SendPan(Gesture::Finished, event);
+                    mState = Finished;
+                    break;
+                  }
+                }
+              }
+              break;
+
+            default:
+              break;
+          }
+        }
+        else
+        {
+          // We have gone outside of the pan requirements, inform Core that the gesture is finished.
+          SendPan(Gesture::Finished, event);
+
+          if (pointCount == 1 && primaryPointState == TouchPoint::Up)
+          {
+            // If this was the primary point being released, then we change our state back to Clear...
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+          else
+          {
+            // ...otherwise we change it to Finished.
+            mState = Finished;
+          }
+        }
+        break;
+      }
+
+      case Finished:
+      case Failed:
+      {
+        if (primaryPointState == TouchPoint::Up)
+        {
+          // Change our state back to clear when the primary touch point is released.
+          mState = Clear;
+          mTouchEvents.clear();
+        }
+        break;
+      }
+    }
+  }
+}
+
+void PanGestureDetectorBase::Update(const Integration::GestureRequest& request)
+{
+  const Integration::PanGestureRequest& pan = static_cast<const Integration::PanGestureRequest&>(request);
+
+  mMinimumTouchesRequired = pan.minTouches;
+  mMaximumTouchesRequired = pan.maxTouches;
+}
+
+void PanGestureDetectorBase::SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent)
+{
+  Integration::PanGestureEvent gesture(state);
+  gesture.currentPosition = currentEvent.points[0].screen;
+  gesture.numberOfTouches = currentEvent.GetPointCount();
+
+  if ( mTouchEvents.size() > 1 )
+  {
+    // Get the second last event in the queue, the last one is the current event
+    const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) );
+
+    Vector2 previousPosition( mPreviousPosition );
+    unsigned long previousTime( previousEvent.time );
+
+    // If we've just started then we want to remove the threshold from Core calculations.
+    if ( state == Gesture::Started )
+    {
+      previousPosition = mPrimaryTouchDownLocation;
+      previousTime = mPrimaryTouchDownTime;
+
+      // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events
+      // A slow pan is defined as one that starts the specified number of milliseconds after the down-event
+      if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS )
+      {
+        mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments;
+        mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / mThresholdTotalAdjustments;
+      }
+      else
+      {
+        mThresholdAdjustmentsRemaining = 0;
+        mThresholdAdjustmentPerFrame = Vector2::ZERO;
+      }
+    }
+
+    gesture.previousPosition = previousPosition;
+    gesture.timeDelta = currentEvent.time - previousTime;
+
+    // Apply the threshold with a phased approach
+    if ( mThresholdAdjustmentsRemaining > 0 )
+    {
+      --mThresholdAdjustmentsRemaining;
+      gesture.currentPosition -= mThresholdAdjustmentPerFrame * mThresholdAdjustmentsRemaining;
+    }
+
+    mPreviousPosition = gesture.currentPosition;
+  }
+  else
+  {
+    gesture.previousPosition = gesture.currentPosition;
+    gesture.timeDelta = 0;
+  }
+
+  gesture.time = currentEvent.time;
+
+  EmitPan(gesture);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/pan-gesture-detector-base.h b/adaptors/common/events/pan-gesture-detector-base.h
new file mode 100644 (file)
index 0000000..3e0f65b
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __DALI_INTERNAL_PAN_GESTURE_DETECTOR_BASE_H__
+#define __DALI_INTERNAL_PAN_GESTURE_DETECTOR_BASE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/integration-api/events/pan-gesture-event.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+struct TouchEvent;
+struct PanGestureRequest;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EnvironmentOptions;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a pan gesture has taken place.
+ */
+class PanGestureDetectorBase : public GestureDetector
+{
+public:
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~PanGestureDetectorBase();
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+   */
+  virtual void SendEvent(const Integration::TouchEvent& event);
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+protected:
+
+  /**
+   * Constructor
+   * @param[in]  screenSize  The size of the screen.
+   * @param[in]  request     The details of the request.
+   */
+  PanGestureDetectorBase(Vector2 screenSize, const Integration::PanGestureRequest& request, EnvironmentOptions* environmentOptions);
+
+private:
+
+  /**
+   * Emits the pan gesture event (performs some smoothing operation).
+   * @param[in]  state         The state of the pan.
+   * @param[in]  currentEvent  The latest touch event.
+   */
+  void SendPan(Gesture::State state, const Integration::TouchEvent& currentEvent);
+
+  /**
+   * Emits the pan gesture event to the core.
+   * @param[in] gesture The pan gesture event.
+   */
+  virtual void EmitPan(const Integration::PanGestureEvent gesture) = 0;
+
+private:
+
+  /**
+   * Internal state machine.
+   */
+  enum State
+  {
+    Clear,    ///< No gesture detected.
+    Possible, ///< The current touch event data suggests that a gesture is possible.
+    Started,  ///< A gesture has been detected.
+    Finished, ///< A previously started pan gesture has finished.
+    Failed,   ///< Current touch event data suggests a pan gesture is not possible.
+  };
+
+  State mState; ///< The current state of the detector.
+  std::vector<Integration::TouchEvent> mTouchEvents;     ///< A container of all touch events after an initial down event.
+
+  Vector2 mPrimaryTouchDownLocation;    ///< The initial touch down point.
+  Vector2 mThresholdAdjustmentPerFrame; ///< The adjustment per frame at the start of a slow pan.
+  Vector2 mPreviousPosition;            ///< The previous position.
+
+  unsigned int mThresholdAdjustmentsRemaining; ///< No. of threshold adjustments still to apply (for a slow-pan).
+  unsigned int mThresholdTotalAdjustments;     ///< The total number of adjustments required.
+
+  unsigned long mPrimaryTouchDownTime;  ///< The initial touch down time.
+  unsigned int mMinimumTouchesRequired; ///< The minimum touches required before a pan should be emitted.
+  unsigned int mMaximumTouchesRequired; ///< The maximum touches after which a pan should not be emitted.
+
+  unsigned int mMinimumDistanceSquared; ///< The minimum distance squared before pan should start.
+  unsigned int mMinimumMotionEvents;    ///< The minimum motion events before pan should start.
+  unsigned int mMotionEvents;           ///< The motion events received so far (before pan is emitted).
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_PAN_GESTURE_DETECTOR_BASE_H__
diff --git a/adaptors/common/events/pan-gesture-detector.cpp b/adaptors/common/events/pan-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..01261d5
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "pan-gesture-detector.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/events/gesture-requests.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+PanGestureDetector::PanGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::PanGestureRequest& request, EnvironmentOptions& environmentOptions)
+: PanGestureDetectorBase(screenSize, request, &environmentOptions),
+  mCoreEventInterface(coreEventInterface)
+{
+}
+
+PanGestureDetector::~PanGestureDetector()
+{
+}
+
+void PanGestureDetector::EmitPan(const Integration::PanGestureEvent event)
+{
+  mCoreEventInterface.QueueCoreEvent(event);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/pan-gesture-detector.h b/adaptors/common/events/pan-gesture-detector.h
new file mode 100644 (file)
index 0000000..71208da
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __DALI_INTERNAL_PAN_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_PAN_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <events/pan-gesture-detector-base.h>
+#include <dali/integration-api/events/pan-gesture-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+struct PanGestureRequest;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CoreEventInterface;
+
+/**
+ * Detects a pan gesture and sends it to core.
+ */
+class PanGestureDetector : public PanGestureDetectorBase
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in] coreEventInterface Used to send events to Core.
+   * @param[in]  screenSize  The size of the screen.
+   * @param[in]  request     The details of the request.
+   * @param[in] environmentOptions The environmentOptions.
+   */
+  PanGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::PanGestureRequest& request, EnvironmentOptions& environmentOptions);
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~PanGestureDetector();
+
+private:
+
+  /**
+   * Emits the pan gesture event to the core.
+   * @param[in] gesture The pan gesture event.
+   */
+  virtual void EmitPan(const Integration::PanGestureEvent gesture);
+
+private:
+
+  CoreEventInterface& mCoreEventInterface; ///< Used to send events to Core.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_PAN_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/events/pinch-gesture-detector.cpp b/adaptors/common/events/pinch-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..5c9c34f
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "pinch-gesture-detector.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/integration-api/events/pinch-gesture-event.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED = 4;
+const unsigned int MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START = 4;
+
+inline float GetDistance(const TouchPoint& point1, const TouchPoint& point2)
+{
+  Vector2 vector(point1.screen - point2.screen);
+  return vector.Length();
+}
+
+inline float GetGradient(const TouchPoint& point1, const TouchPoint& point2)
+{
+  return (point2.screen.y - point1.screen.y)
+         /
+         (point2.screen.x - point1.screen.x);
+}
+
+inline Vector2 GetCenterPoint(const TouchPoint& point1, const TouchPoint& point2)
+{
+  return Vector2(point1.screen + point2.screen) * 0.5f;
+}
+
+} // unnamed namespace
+
+PinchGestureDetector::PinchGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, float minimumPinchDistance)
+: GestureDetector(screenSize, Gesture::Pinch),
+  mCoreEventInterface(coreEventInterface),
+  mState(Clear),
+  mTouchEvents(),
+  mMinimumDistanceDelta(minimumPinchDistance),
+  mStartingDistance(0.0f)
+{
+}
+
+PinchGestureDetector::~PinchGestureDetector()
+{
+}
+
+void PinchGestureDetector::SetMinimumPinchDistance(float distance)
+{
+  mMinimumDistanceDelta = distance;
+}
+
+void PinchGestureDetector::SendEvent(const Integration::TouchEvent& event)
+{
+  int pointCount = event.GetPointCount();
+
+  switch (mState)
+  {
+    case Clear:
+    {
+      if (pointCount == 2)
+      {
+        // Change state to possible as we have two touch points.
+        mState = Possible;
+        mTouchEvents.push_back(event);
+      }
+      break;
+    }
+
+    case Possible:
+    {
+      if (pointCount != 2)
+      {
+        // We no longer have two touch points so change state back to Clear.
+        mState = Clear;
+        mTouchEvents.clear();
+      }
+      else
+      {
+        const TouchPoint& currentPoint1 = event.points[0];
+        const TouchPoint& currentPoint2 = event.points[1];
+
+        if (currentPoint1.state == TouchPoint::Up || currentPoint2.state == TouchPoint::Up)
+        {
+          // One of our touch points has an Up event so change our state back to Clear.
+          mState = Clear;
+          mTouchEvents.clear();
+        }
+        else
+        {
+          mTouchEvents.push_back(event);
+
+          // We can only determine a pinch after a certain number of touch points have been collected.
+          if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED)
+          {
+            const TouchPoint& firstPoint1 = mTouchEvents[0].points[0];
+            const TouchPoint& firstPoint2 = mTouchEvents[0].points[1];
+
+            float firstDistance = GetDistance(firstPoint1, firstPoint2);
+            float currentDistance = GetDistance(currentPoint1, currentPoint2);
+            float distanceChanged = firstDistance - currentDistance;
+
+            // Check if distance has changed enough
+            if (fabsf(distanceChanged) > mMinimumDistanceDelta)
+            {
+              // Remove the first few events from the vector otherwise values are exaggerated
+              mTouchEvents.erase(mTouchEvents.begin(), mTouchEvents.end() - MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START);
+
+              if ( !mTouchEvents.empty() )
+              {
+                mStartingDistance = GetDistance(mTouchEvents.begin()->points[0], mTouchEvents.begin()->points[1]);
+
+                // Send pinch started
+                SendPinch(Gesture::Started, event);
+
+                mState = Started;
+              }
+
+              mTouchEvents.clear();
+            }
+
+            if (mState == Possible)
+            {
+              // No pinch, so restart detection
+              mState = Clear;
+              mTouchEvents.clear();
+            }
+          }
+        }
+      }
+      break;
+    }
+
+    case Started:
+    {
+      if (pointCount != 2)
+      {
+        // Send pinch finished event
+        SendPinch(Gesture::Finished, event);
+
+        mState = Clear;
+        mTouchEvents.clear();
+      }
+      else
+      {
+        const TouchPoint& currentPoint1 = event.points[0];
+        const TouchPoint& currentPoint2 = event.points[1];
+
+        if (currentPoint1.state == TouchPoint::Up || currentPoint2.state == TouchPoint::Up)
+        {
+          mTouchEvents.push_back(event);
+          // Send pinch finished event
+          SendPinch(Gesture::Finished, event);
+
+          mState = Clear;
+          mTouchEvents.clear();
+        }
+        else
+        {
+          mTouchEvents.push_back(event);
+
+          if (mTouchEvents.size() >= MINIMUM_TOUCH_EVENTS_REQUIRED_AFTER_START)
+          {
+            // Send pinch continuing
+            SendPinch(Gesture::Continuing, event);
+
+            mTouchEvents.clear();
+          }
+        }
+      }
+      break;
+    }
+  }
+}
+
+void PinchGestureDetector::Update(const Integration::GestureRequest& request)
+{
+  // Nothing to do.
+}
+
+void PinchGestureDetector::SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent)
+{
+  Integration::PinchGestureEvent gesture(state);
+
+  if ( !mTouchEvents.empty() )
+  {
+    const Integration::TouchEvent& firstEvent = mTouchEvents[0];
+
+    // Assert if we have been holding TouchEvents that do not have 2 points
+    DALI_ASSERT_DEBUG( firstEvent.GetPointCount() == 2 );
+
+    // We should use the current event in our calculations unless it does not have two points.
+    // If it does not have two points, then we should use the last point in mTouchEvents.
+    Integration::TouchEvent event( currentEvent );
+    if ( event.GetPointCount() != 2 )
+    {
+      event = *mTouchEvents.rbegin();
+    }
+
+    const TouchPoint& firstPoint1( firstEvent.points[0] );
+    const TouchPoint& firstPoint2( firstEvent.points[1] );
+    const TouchPoint& currentPoint1( event.points[0] );
+    const TouchPoint& currentPoint2( event.points[1] );
+
+    float firstDistance = GetDistance(firstPoint1, firstPoint2);
+    float currentDistance = GetDistance(currentPoint1, currentPoint2);
+    gesture.scale = currentDistance / mStartingDistance;
+
+    float distanceDelta = fabsf(firstDistance - currentDistance);
+    unsigned long timeDelta = currentEvent.time - firstEvent.time;
+    gesture.speed = (distanceDelta / timeDelta) * 1000.0f;
+
+    gesture.centerPoint = GetCenterPoint(currentPoint1, currentPoint2);
+  }
+  else
+  {
+    // Something has gone wrong, just cancel the gesture.
+    gesture.state = Gesture::Cancelled;
+  }
+
+  gesture.time = currentEvent.time;
+
+  mCoreEventInterface.QueueCoreEvent(gesture);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/pinch-gesture-detector.h b/adaptors/common/events/pinch-gesture-detector.h
new file mode 100644 (file)
index 0000000..ffd0eaf
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CoreEventInterface;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a pinch gesture has taken place.
+ */
+class PinchGestureDetector : public GestureDetector
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in] coreEventInterface Used to send events to Core.
+   * @param[in] screenSize The size of the screen.
+   */
+  PinchGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, float minimumPinchDistance);
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~PinchGestureDetector();
+
+  /**
+   * @brief Sets minimum distance in pixels that the fingers must move towards/away from each other in order to
+   * trigger a pinch gesture
+   *
+   * @param[in] distance The minimum pinch distance in pixels
+   */
+  void SetMinimumPinchDistance(float distance);
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+   */
+  virtual void SendEvent(const Integration::TouchEvent& event);
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+private:
+
+  /**
+   * Emits the pinch gesture event to the core.
+   * @param[in]  state         The state of the pinch (whether it's starting, continuing or finished).
+   * @param[in]  currentEvent  The latest touch event.
+   */
+  void SendPinch(Gesture::State state, const Integration::TouchEvent& currentEvent);
+
+private:
+
+  /**
+   * Internal state machine.
+   */
+  enum State
+  {
+    Clear,    ///< No gesture detected.
+    Possible, ///< The current touch event data suggests that a gesture is possible.
+    Started,  ///< A gesture has been detected.
+  };
+
+  CoreEventInterface& mCoreEventInterface; ///< Used to send events to Core.
+  State mState; ///< The current state of the detector.
+  std::vector<Integration::TouchEvent> mTouchEvents; ///< The touch events since initial touch down.
+
+  float mMinimumDistanceDelta; ///< The minimum distance before a pinch is applicable.
+
+  float mStartingDistance; ///< The distance between the two touch points when the pinch is first detected.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_PINCH_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/events/tap-gesture-detector.cpp b/adaptors/common/events/tap-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..af7949b
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tap-gesture-detector.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/math/vector2.h>
+
+#include <dali/integration-api/events/gesture-requests.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <base/core-event-interface.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// TODO: Set these according to DPI
+const float MAXIMUM_MOTION_ALLOWED = 20.0f;
+const unsigned long MAXIMUM_TIME_ALLOWED = 500u;
+} // unnamed namespace
+
+TapGestureDetector::TapGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::TapGestureRequest& request)
+: GestureDetector(screenSize, Gesture::Tap),
+  mCoreEventInterface(coreEventInterface),
+  mState(Clear),
+  mMinimumTapsRequired(request.minTaps),
+  mMaximumTapsRequired(request.maxTaps),
+  mTapsRegistered(0),
+  mTouchPosition(),
+  mTouchTime(0u),
+  mLastTapTime(0u)
+{
+}
+
+TapGestureDetector::~TapGestureDetector()
+{
+}
+
+void TapGestureDetector::SendEvent(const Integration::TouchEvent& event)
+{
+  if (event.GetPointCount() == 1)
+  {
+    const TouchPoint& point = event.points[0];
+    TouchPoint::State pointState = point.state;
+
+    switch (mState)
+    {
+      case Clear:
+      {
+        if (pointState == TouchPoint::Down)
+        {
+          SetupForTouchDown( event, point );
+        }
+        break;
+      }
+
+      case Touched:
+      {
+        unsigned long deltaBetweenTouchDownTouchUp = abs( event.time - mTouchTime ) ;
+
+        if ( pointState == TouchPoint::Up )
+        {
+          if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
+          {
+            mLastTapTime = mTouchTime;
+            EmitSingleTap( event.time, point );
+            mState = Registered;
+          }
+          else
+          {
+            mState = Clear;
+          }
+        }
+        else if (pointState == TouchPoint::Interrupted)
+        {
+          mState = Clear;
+        }
+        break;
+      }
+
+      case Registered:
+      {
+        if ( pointState == TouchPoint::Up )
+        {
+          unsigned long deltaBetweenTouchDownTouchUp = abs( event.time - mTouchTime ) ;
+
+          if ( deltaBetweenTouchDownTouchUp < MAXIMUM_TIME_ALLOWED )
+          {
+            // This is a possible multiple tap, so has it been quick enough ?
+            unsigned long timeDelta = abs( event.time - mLastTapTime );
+            if ( timeDelta > MAXIMUM_TIME_ALLOWED ) // If exceeded time between taps then just a single tap.
+            {
+              mLastTapTime = event.time;
+              EmitSingleTap( event.time, point );
+              mState = Registered;
+            }
+            else
+            {
+              ++mTapsRegistered;
+              EmitGesture( Gesture::Started, event.time );
+              mState = Clear;
+            }
+          }
+          else // Delta between touch down and touch up too long to be considered a Tap event
+          {
+            mState = Clear;
+          }
+        }
+        else if (pointState == TouchPoint::Down)
+        {
+          Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
+                                abs(mTouchPosition.y - point.screen.y));
+
+          unsigned long timeDelta = abs( event.time - mLastTapTime );
+
+          if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
+              distanceDelta.y > MAXIMUM_MOTION_ALLOWED ||
+              timeDelta > MAXIMUM_TIME_ALLOWED )
+          {
+            SetupForTouchDown( event, point );
+          }
+          else
+          {
+            EmitPossibleState( event );
+          }
+        }
+        break;
+      }
+
+      case Failed:
+      default:
+      {
+        mState = Clear;
+        break;
+      }
+    }
+  }
+  else
+  {
+    mState = Failed;
+
+    // We have entered a multi-touch event so emit registered gestures if required.
+    EmitGesture(Gesture::Started, event.time);
+  }
+}
+
+void TapGestureDetector::SetupForTouchDown( const Integration::TouchEvent& event, const TouchPoint& point )
+{
+  mTouchPosition.x = point.screen.x;
+  mTouchPosition.y = point.screen.y;
+  mTouchTime = event.time;
+  mLastTapTime = 0u;
+  mTapsRegistered = 0;
+  mState = Touched;
+  EmitPossibleState( event );
+}
+
+void TapGestureDetector::EmitPossibleState( const Integration::TouchEvent& event )
+{
+  Integration::TapGestureEvent tapEvent( Gesture::Possible );
+  tapEvent.point = mTouchPosition;
+  tapEvent.time = event.time;
+  mCoreEventInterface.QueueCoreEvent(tapEvent);
+}
+
+
+void TapGestureDetector::Update(const Integration::GestureRequest& request)
+{
+  const Integration::TapGestureRequest& tap = static_cast<const Integration::TapGestureRequest&>(request);
+
+  mMinimumTapsRequired = tap.minTaps;
+  mMaximumTapsRequired = tap.maxTaps;
+}
+
+void TapGestureDetector::EmitGesture( Gesture::State state, unsigned int time )
+{
+  if ( (state == Gesture::Cancelled) ||
+       (mTapsRegistered >= mMinimumTapsRequired && mTapsRegistered <= mMaximumTapsRequired) )
+
+  {
+    Integration::TapGestureEvent event( state );
+    EmitTap( time, event );
+  }
+}
+
+void TapGestureDetector::EmitSingleTap( unsigned int time, const TouchPoint& point )
+{
+  Integration::TapGestureEvent event( Gesture::Started );
+  Vector2 distanceDelta(abs(mTouchPosition.x - point.screen.x),
+                        abs(mTouchPosition.y - point.screen.y));
+
+  if (distanceDelta.x > MAXIMUM_MOTION_ALLOWED ||
+      distanceDelta.y > MAXIMUM_MOTION_ALLOWED )
+  {
+    event.state = Gesture::Cancelled;
+  }
+  mTapsRegistered = 1u;
+  EmitTap( time, event );
+}
+
+void TapGestureDetector::EmitTap( unsigned int time, Integration::TapGestureEvent& event )
+{
+  event.numberOfTaps = mTapsRegistered;
+  event.point = mTouchPosition;
+  event.time = time;
+  mCoreEventInterface.QueueCoreEvent(event);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/events/tap-gesture-detector.h b/adaptors/common/events/tap-gesture-detector.h
new file mode 100644 (file)
index 0000000..8182784
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef __DALI_INTERNAL_TAP_GESTURE_DETECTOR_H__
+#define __DALI_INTERNAL_TAP_GESTURE_DETECTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/events/tap-gesture-event.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/touch-point.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+struct TapGestureRequest;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class CoreEventInterface;
+
+/**
+ * When given a set of touch events, this detector attempts to determine if a tap gesture has taken place.
+ */
+class TapGestureDetector : public GestureDetector
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in] coreEventInterface Used to send events to Core.
+   * @param[in]  screenSize  The size of the screen.
+   * @param[in]  request     The tap gesture request.
+   */
+  TapGestureDetector(CoreEventInterface& coreEventInterface, Vector2 screenSize, const Integration::TapGestureRequest& request);
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~TapGestureDetector();
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::SendEvent(const Integration::TouchEvent&)
+   */
+  virtual void SendEvent(const Integration::TouchEvent& event);
+
+  /**
+   * @copydoc Dali::Internal::GestureDetector::Update(const Integration::GestureRequest&)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+private:
+
+  /**
+   * Checks if registered taps are within required bounds and emits tap gesture if they are.
+   *
+   * @param[in] state current state of incomplete gesture
+   * @param[in] time time of this latest touch event
+   */
+  void EmitGesture( Gesture::State state, unsigned int time );
+
+  /**
+   * Initialises tap gesture detector for next tap sequence
+   *
+   * @param[in] event registered touch event
+   * @param[in] point position touch event occurred
+   */
+  void SetupForTouchDown( const Integration::TouchEvent& event, const TouchPoint& point );
+
+  /**
+   * Emit a touch down event for hit testing
+   *
+   * @param[in] event registered touch event
+   */
+  void EmitPossibleState( const Integration::TouchEvent& event );
+
+  /**
+   * Force a touch event sequence to be treated as a single tap
+   *
+   * @param[in] time time of this latest touch event
+   * @param[in] point position touch event occurred
+    */
+  void EmitSingleTap( unsigned int time, const TouchPoint& point );
+
+  /**
+   * Emit a tap event
+   *
+   * @param[in] time time of this latest touch event
+   * @param[in] event registered touch event
+   */
+  void EmitTap( unsigned int time, Integration::TapGestureEvent& event );
+
+private:
+
+  /**
+   * Internal state machine.
+   */
+  enum State
+  {
+    Clear,      ///< No gesture detected.
+    Touched,    ///< User is touching the screen.
+    Registered, ///< At least one tap has been registered.
+    Failed,     ///< Gesture has failed.
+  };
+
+  CoreEventInterface& mCoreEventInterface; ///< Used to send events to Core.
+  State mState; ///< Current state of the detector.
+
+  int mMinimumTapsRequired; ///< Minimum number of taps required.
+  int mMaximumTapsRequired; ///< Maximum number of taps required.
+  int mTapsRegistered;      ///< In current detection, the number of taps registered.
+
+  Vector2 mTouchPosition;   ///< The initial touch down position.
+  unsigned long mTouchTime; ///< The initial touch down time.
+  unsigned long mLastTapTime; ///< Time last tap gesture was registered
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TAP_GESTURE_DETECTOR_H__
diff --git a/adaptors/common/feedback-player-impl.cpp b/adaptors/common/feedback-player-impl.cpp
new file mode 100644 (file)
index 0000000..29a9a86
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <feedback-player-impl.h>
+
+// EXTERNAL INCLUDES
+#include <fstream>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return FeedbackPlayer::Get();
+}
+
+Dali::TypeRegistration FEEDBACK_PLAYER_TYPE( typeid(Dali::FeedbackPlayer), typeid(Dali::BaseHandle), Create );
+
+} // unnamed namespace
+
+Dali::FeedbackPlayer FeedbackPlayer::New()
+{
+  Dali::FeedbackPlayer player = Dali::FeedbackPlayer( new FeedbackPlayer() );
+  return player;
+}
+
+Dali::FeedbackPlayer FeedbackPlayer::Get()
+{
+  Dali::FeedbackPlayer player;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::FeedbackPlayer ) );
+    if ( handle )
+    {
+      // If so, downcast the handle
+      player = Dali::FeedbackPlayer( dynamic_cast< FeedbackPlayer* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      player = Dali::FeedbackPlayer( New() );
+      service.Register( typeid( player ), player );
+    }
+  }
+
+  return player;
+}
+
+void FeedbackPlayer::PlayMonotone( unsigned int duration )
+{
+  mPlugin.PlayHapticMonotone( duration );
+}
+
+void FeedbackPlayer::PlayFile( const std::string& filePath )
+{
+  mPlugin.PlayHaptic( filePath );
+}
+
+void FeedbackPlayer::Stop()
+{
+  mPlugin.StopHaptic();
+}
+
+int FeedbackPlayer::PlaySound( const std::string& filename )
+{
+  return mPlugin.PlaySound(filename);
+}
+
+void FeedbackPlayer::StopSound( int handle )
+{
+  mPlugin.StopSound(handle);
+}
+
+void FeedbackPlayer::PlayFeedbackPattern( int type, int pattern )
+{
+  mPlugin.PlayFeedbackPattern(type, pattern);
+}
+
+bool FeedbackPlayer::LoadFile(const std::string& filename, std::string& data)
+{
+  bool loaded = false;
+
+  std::ifstream stream(filename.c_str());
+
+  if( stream.is_open() )
+  {
+    data.assign((std::istreambuf_iterator<char>(stream)),
+                std::istreambuf_iterator<char>());
+    loaded = true;
+  }
+
+  return loaded;
+}
+
+FeedbackPlayer::FeedbackPlayer()
+: mPlugin( FeedbackPluginProxy::DEFAULT_OBJECT_NAME )
+{
+}
+
+FeedbackPlayer::~FeedbackPlayer()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/feedback-player-impl.h b/adaptors/common/feedback-player-impl.h
new file mode 100644 (file)
index 0000000..937a36a
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef __DALI_INTERNAL_FEEDBACK_PLAYER_H__
+#define __DALI_INTERNAL_FEEDBACK_PLAYER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <feedback-player.h>
+#include <feedback/feedback-plugin-proxy.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class FeedbackPluginProxy;
+
+/**
+ * Plays haptic effects.
+ */
+class FeedbackPlayer : public Dali::BaseObject
+{
+
+public:
+
+  /**
+   * Create a FeedbackPlayer.
+   * This should only be called once by the Adaptor class.
+   * @return A newly created FeedbackPlayer.
+   */
+  static Dali::FeedbackPlayer New();
+
+  /**
+   * Retrieve a handle to the FeedbackPlayer. This creates an instance if none has been created.
+   * @return A handle to the FeedbackPlayer.
+   */
+  static Dali::FeedbackPlayer Get();
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayMonotone()
+   */
+  void PlayMonotone(unsigned int duration);
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayFile()
+   */
+  void PlayFile( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::LoadFile()
+   */
+  bool LoadFile(const std::string& filename, std::string& data);
+
+private:
+
+  /**
+   * Private Constructor; see also FeedbackPlayer::New()
+   */
+  FeedbackPlayer();
+
+  /**
+   * Virtual Destructor
+   */
+  virtual ~FeedbackPlayer();
+
+  // Undefined
+  FeedbackPlayer(const FeedbackPlayer&);
+
+  // Undefined
+  FeedbackPlayer& operator=(FeedbackPlayer&);
+
+private:
+
+  FeedbackPluginProxy mPlugin;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::FeedbackPlayer& GetImplementation(Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::FeedbackPlayer& GetImplementation(const Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_FEEDBACK_PLAYER_H__
diff --git a/adaptors/common/feedback/feedback-plugin-proxy.cpp b/adaptors/common/feedback/feedback-plugin-proxy.cpp
new file mode 100644 (file)
index 0000000..2777e21
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <feedback/feedback-plugin-proxy.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+const char * const FeedbackPluginProxy::DEFAULT_OBJECT_NAME( "libdali-feedback-plugin.so" );
+
+FeedbackPluginProxy::FeedbackPluginProxy( const std::string& sharedObjectName )
+: mInitializeAttempted( false ),
+  mLibHandle( NULL ),
+  mSharedObjectName( sharedObjectName ),
+  mCreatePluginFunctionPtr( NULL ),
+  mFeedbackPlugin( NULL )
+{
+  // Lazily initialize when sound/haptic is first played
+}
+
+FeedbackPluginProxy::~FeedbackPluginProxy()
+{
+  if( mFeedbackPlugin )
+  {
+    delete mFeedbackPlugin;
+    mFeedbackPlugin = NULL;
+
+    if( mLibHandle && dlclose( mLibHandle ) )
+    {
+      DALI_LOG_ERROR( "Error closing dali feedback plugin library: %s\n", dlerror() );
+    }
+  }
+}
+
+void FeedbackPluginProxy::PlayHaptic( const std::string& filePath )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayHaptic( filePath );
+  }
+}
+
+void FeedbackPluginProxy::PlayHapticMonotone( unsigned int duration )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayHapticMonotone( duration );
+  }
+}
+
+void FeedbackPluginProxy::StopHaptic()
+{
+  // Must already have been initialized to play haptic
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->StopHaptic();
+  }
+}
+
+int FeedbackPluginProxy::PlaySound( const std::string& fileName )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    return mFeedbackPlugin->PlaySound( fileName );
+  }
+
+  return 0;
+}
+
+void FeedbackPluginProxy::StopSound( int handle )
+{
+  // Must already have been initialized to play sound
+  if ( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->StopSound( handle );
+  }
+}
+
+void FeedbackPluginProxy::PlayFeedbackPattern( int type, int pattern )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayFeedbackPattern( type, pattern );
+  }
+}
+
+void FeedbackPluginProxy::Initialize()
+{
+  // Only attempt to load dll once
+  if ( !mInitializeAttempted )
+  {
+    mInitializeAttempted = true;
+
+    mLibHandle = dlopen( mSharedObjectName.c_str(), RTLD_NOW | RTLD_GLOBAL );
+    if( !mLibHandle )
+    {
+      DALI_LOG_ERROR( "Cannot load dali feedback plugin library error: %s\n", dlerror() );
+      return;
+    }
+
+    // reset errors
+    dlerror();
+
+    // load plugin
+    mCreatePluginFunctionPtr = reinterpret_cast<CreateFeedbackPlugin*>(dlsym(mLibHandle, "CreateFeedbackPlugin"));
+    if(!mCreatePluginFunctionPtr)
+    {
+      DALI_LOG_ERROR("Cannot load symbol CreateFeedbackPlugin(): %s\n", dlerror());
+      return;
+    }
+
+    // reset errors
+    dlerror();
+
+    mFeedbackPlugin = mCreatePluginFunctionPtr();
+
+    if(!mFeedbackPlugin)
+    {
+      DALI_LOG_ERROR("Call to function CreateFeedbackPlugin() failed\n");
+    }
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/feedback/feedback-plugin-proxy.h b/adaptors/common/feedback/feedback-plugin-proxy.h
new file mode 100644 (file)
index 0000000..e04f22b
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef __DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H__
+#define __DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+// INTERNAL INCLUDES
+#include <feedback-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+typedef Dali::FeedbackPlugin::SoundStopCallBack SoundStopCallBack;
+typedef Dali::FeedbackPlugin::CreateFeedbackPlugin CreateFeedbackPlugin;
+
+/**
+ * Proxy class to dynamically load, use and unload feedback plugin.
+ */
+class FeedbackPluginProxy
+{
+public:
+
+  /**
+   * The default feedback plugin proxy.
+   */
+  static const char * const DEFAULT_OBJECT_NAME;
+
+public:
+
+  /**
+   * Constructor.
+   */
+  FeedbackPluginProxy( const std::string& sharedObjectName );
+
+  /**
+   * The destructor
+   */
+  ~FeedbackPluginProxy();
+
+  /**
+   * @copydoc Dali::Integration::FeedbackPlugin::PlayHaptic()
+   */
+  void PlayHaptic( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayHapticMonotone()
+   */
+  void PlayHapticMonotone( unsigned int duration );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopHaptic()
+   */
+  void StopHaptic();
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+private:
+
+  /**
+   * Dynamically loads the feedback plugin.
+   */
+  void Initialize();
+
+private:
+
+  bool mInitializeAttempted;
+  void* mLibHandle;
+  std::string mSharedObjectName;
+  CreateFeedbackPlugin* mCreatePluginFunctionPtr;
+  Dali::FeedbackPlugin* mFeedbackPlugin;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H__
diff --git a/adaptors/common/file-descriptor-monitor.h b/adaptors/common/file-descriptor-monitor.h
new file mode 100644 (file)
index 0000000..9ffd738
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef __DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H__
+#define __DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Monitors the given file descriptor and whenever anything is written to it, the provided
+ * callback is called
+ */
+class FileDescriptorMonitor
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in]  fileDescriptor  The file descriptor to monitor
+   * @param[in]  callback        Called when anything is written to the file descriptor
+   * @note The ownership of callback is taken by this class.
+   */
+  FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback );
+
+  /**
+   * Destructor
+   */
+  ~FileDescriptorMonitor();
+
+private:
+
+  // Undefined
+  FileDescriptorMonitor( const FileDescriptorMonitor& fileDescriptorMonitor );
+
+  // Undefined
+  FileDescriptorMonitor& operator=( const FileDescriptorMonitor& fileDescriptorMonitor );
+
+private:
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H__
diff --git a/adaptors/common/file.list b/adaptors/common/file.list
new file mode 100644 (file)
index 0000000..b30b3fe
--- /dev/null
@@ -0,0 +1,66 @@
+# Common
+
+adaptor_common_internal_src_files = \
+  $(adaptor_common_dir)/abort-handler.cpp \
+  $(adaptor_common_dir)/accessibility-gesture-detector.cpp \
+  $(adaptor_common_dir)/adaptor.cpp \
+  $(adaptor_common_dir)/adaptor-impl.cpp \
+  $(adaptor_common_dir)/application-impl.cpp \
+  $(adaptor_common_dir)/bitmap-loader-impl.cpp \
+  $(adaptor_common_dir)/clipboard-event-notifier-impl.cpp \
+  $(adaptor_common_dir)/command-line-options.cpp \
+  $(adaptor_common_dir)/drag-and-drop-detector-impl.cpp \
+  $(adaptor_common_dir)/feedback-player-impl.cpp \
+  $(adaptor_common_dir)/indicator-impl.cpp \
+  $(adaptor_common_dir)/indicator-buffer.cpp \
+  $(adaptor_common_dir)/kernel-trace.cpp \
+  $(adaptor_common_dir)/system-trace.cpp \
+  $(adaptor_common_dir)/lifecycle-controller-impl.cpp \
+  $(adaptor_common_dir)/locale-utils.cpp  \
+  $(adaptor_common_dir)/native-bitmap-buffer-impl.cpp \
+  $(adaptor_common_dir)/object-profiler.cpp \
+  $(adaptor_common_dir)/orientation-impl.cpp  \
+  $(adaptor_common_dir)/performance-logger-impl.cpp \
+  $(adaptor_common_dir)/physical-keyboard-impl.cpp \
+  $(adaptor_common_dir)/server-connection.cpp \
+  $(adaptor_common_dir)/shared-file.cpp \
+  $(adaptor_common_dir)/singleton-service-impl.cpp \
+  $(adaptor_common_dir)/sound-player-impl.cpp \
+  $(adaptor_common_dir)/style-monitor-impl.cpp \
+  $(adaptor_common_dir)/trigger-event.cpp \
+  $(adaptor_common_dir)/trigger-event-factory.cpp \
+  $(adaptor_common_dir)/virtual-keyboard-impl.cpp \
+  $(adaptor_common_dir)/key-impl.cpp \
+  \
+  $(adaptor_common_dir)/events/gesture-manager.cpp \
+  $(adaptor_common_dir)/events/long-press-gesture-detector.cpp \
+  $(adaptor_common_dir)/events/pan-gesture-detector-base.cpp \
+  $(adaptor_common_dir)/events/pan-gesture-detector.cpp \
+  $(adaptor_common_dir)/events/pinch-gesture-detector.cpp \
+  $(adaptor_common_dir)/events/tap-gesture-detector.cpp \
+  \
+  $(adaptor_common_dir)/networking/socket-impl.cpp \
+  $(adaptor_common_dir)/networking/socket-factory.cpp \
+  \
+  $(adaptor_common_dir)/feedback/feedback-plugin-proxy.cpp \
+  \
+  $(adaptor_common_dir)/gl/egl-factory.cpp \
+  $(adaptor_common_dir)/gl/egl-image-extensions.cpp \
+  $(adaptor_common_dir)/gl/egl-sync-implementation.cpp \
+  $(adaptor_common_dir)/gl/gl-proxy-implementation.cpp \
+  $(adaptor_common_dir)/gl/gl-extensions.cpp
+
+# Different files depending on the event loop being used
+adaptor_common_internal_ecore_src_files = \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-callback-manager.cpp \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-file-descriptor-monitor.cpp \
+  $(adaptor_common_dir)/event-loop/ecore/ecore-timer-impl.cpp
+
+ adaptor_common_internal_uv_src_files = \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-callback-manager.cpp \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-file-descriptor-monitor.cpp \
+  $(adaptor_common_dir)/event-loop/lib-uv/uv-timer-impl.cpp
+
+adaptor_common_internal_default_profile_src_files = \
+  $(adaptor_common_dir)/color-controller-impl.cpp \
+  $(adaptor_common_dir)/system-settings.cpp
diff --git a/adaptors/common/framework.h b/adaptors/common/framework.h
new file mode 100644 (file)
index 0000000..3704431
--- /dev/null
@@ -0,0 +1,213 @@
+#ifndef __DALI_INTERNAL_FRAMEWORK_H__
+#define __DALI_INTERNAL_FRAMEWORK_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include "abort-handler.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * The Framework class is used to register callbacks with the TIZEN platform so that
+ * we know when any of the application lifecycle events occur.  This includes events
+ * like when our application is to be initialised, terminated, paused, resumed etc.
+ */
+class Framework
+{
+public:
+
+  /**
+   * Observer class for the framework.
+   */
+  class Observer
+  {
+  public:
+
+    /**
+     * Invoked when the application is to be initialised.
+     */
+    virtual void OnInit() {}
+
+    /**
+     * Invoked when the application is to be terminated.
+     */
+    virtual void OnTerminate() {}
+
+    /**
+     * Invoked when the application is to be paused.
+     */
+    virtual void OnPause() {}
+
+    /**
+     * Invoked when the application is to be resumed.
+     */
+    virtual void OnResume() {}
+
+    /**
+     * Invoked when the application is to be reset.
+     */
+    virtual void OnReset() {}
+
+    /**
+    * Invoked when the AppControl message is received.
+    * @param[in] The bundle data of AppControl message.
+    */
+    virtual void OnAppControl(void *) {}
+
+    /**
+     * Invoked when the language of the device is changed.
+     */
+    virtual void OnLanguageChanged() {}
+
+    /**
+    * Invoked when the region is changed.
+    */
+    virtual void OnRegionChanged() {}
+
+    /**
+    * Invoked when the battery level of the device is low.
+    */
+    virtual void OnBatteryLow() {}
+
+    /**
+    * Invoked when the memory level of the device is low.
+    */
+    virtual void OnMemoryLow() {}
+  };
+
+public:
+
+  /**
+   * Constructor
+   * @param[in]  observer  The observer of the Framework.
+   * @param[in]  argc      A pointer to the number of arguments.
+   * @param[in]  argv      A pointer the the argument list.
+   */
+  Framework( Observer& observer, int* argc, char ***argv );
+
+  /**
+   * Destructor
+   */
+  ~Framework();
+
+public:
+
+  /**
+   * Runs the main loop of framework
+   */
+  void Run();
+
+  /**
+   * Quits the main loop
+   */
+  void Quit();
+
+  /**
+   * Checks whether the main loop of the framework is running.
+   * @return true, if the main loop is running, false otherwise.
+   */
+  bool IsMainLoopRunning();
+
+  /**
+   * If the main loop aborts unexpectedly, then the connected callback function is called.
+   * @param[in]  callBack  The function to call.
+   * @note Only one callback can be registered.  The last callback to be set will be called on abort.
+   * @note The ownership of callback is passed onto this class.
+   */
+  void AddAbortCallback( CallbackBase* callback );
+
+  /**
+   * Gets bundle name which was passed in app_reset callback.
+   */
+  std::string GetBundleName() const;
+
+  /**
+   * Gets bundle id which was passed in app_reset callback.
+   */
+  std::string GetBundleId() const;
+
+private:
+
+  // Undefined
+  Framework(const Framework&);
+  Framework& operator=(Framework&);
+
+private:
+  /**
+   * Called by the App framework when an application lifecycle event occurs.
+   * @param[in] type The type of event occurred.
+   * @param[in] bundleData The bundle data of event occurred.
+   */
+  bool AppStatusHandler(int type, void *bundleData);
+
+  /**
+   * Called app_reset callback was called with bundle.
+   */
+  void SetBundleName(const std::string& name);
+
+  /**
+   * Called app_reset callback was called with bundle.
+   */
+  void SetBundleId(const std::string& id);
+
+  /**
+   * Called if the application is aborted.
+   */
+  void AbortCallback();
+
+  /**
+   * Called for initializing on specified backend. (X11 or Wayland)
+   */
+  void InitThreads();
+
+private:
+  Observer&          mObserver;
+  bool               mInitialised;
+  bool               mRunning;
+  int*               mArgc;
+  char***            mArgv;
+  std::string        mBundleName;
+  std::string        mBundleId;
+  AbortHandler       mAbortHandler;
+
+private: // impl members
+
+  struct Impl;
+  Impl* mImpl;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_FRAMEWORK_H__
diff --git a/adaptors/common/gl/egl-factory.cpp b/adaptors/common/gl/egl-factory.cpp
new file mode 100644 (file)
index 0000000..1301016
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "egl-factory.h"
+
+// INTERNAL INCLUDES
+#include <gl/egl-implementation.h>
+#include <gl/egl-image-extensions.h>
+#include <gl/egl-sync-implementation.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+EglFactory::EglFactory()
+: mEglImplementation(NULL),
+  mEglImageExtensions(NULL),
+  mEglSync(new EglSyncImplementation) // Created early, as needed by Core constructor
+{
+}
+
+EglFactory::~EglFactory()
+{
+  // Ensure the EGL implementation is destroyed
+  delete mEglImageExtensions;
+  delete mEglImplementation;
+  delete mEglSync;
+}
+
+EglInterface* EglFactory::Create()
+{
+  // Created by RenderThread (After Core construction)
+  mEglImplementation = new EglImplementation();
+  mEglImageExtensions = new EglImageExtensions(mEglImplementation);
+
+  mEglSync->Initialize(mEglImplementation); // The sync impl needs the EglDisplay
+  return mEglImplementation;
+}
+
+void EglFactory::Destroy()
+{
+  delete mEglImageExtensions;
+  mEglImageExtensions = NULL;
+  delete mEglImplementation;
+  mEglImplementation = NULL;
+}
+
+EglInterface* EglFactory::GetImplementation()
+{
+  return mEglImplementation;
+}
+
+EglImageExtensions* EglFactory::GetImageExtensions()
+{
+  return mEglImageExtensions;
+}
+
+EglSyncImplementation* EglFactory::GetSyncImplementation()
+{
+  return mEglSync;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/gl/egl-factory.h b/adaptors/common/gl/egl-factory.h
new file mode 100644 (file)
index 0000000..a97d555
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_EGL_FACTORY_IMPL_H__
+#define __DALI_INTERNAL_ADAPTOR_EGL_FACTORY_IMPL_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <base/interfaces/egl-factory-interface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EglImplementation;
+class EglImageExtensions;
+class EglSyncImplementation;
+
+class EglFactory : public EglFactoryInterface
+{
+public:
+  /**
+   * Constructor
+   */
+  EglFactory();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglFactory();
+
+  /**
+   * Create an EGL Implementation
+   * @return[in] An implementation
+   */
+  EglInterface* Create();
+
+  /**
+   * Destroy the EGL Implementation
+   */
+  void Destroy();
+
+  /**
+   * Get an implementation if one has been created.
+   * @return An implementation, or NULL if one has not yet been created.
+   */
+  EglInterface* GetImplementation();
+
+  /**
+   * Get the image extension
+   */
+  EglImageExtensions* GetImageExtensions();
+
+  /**
+   * Get the fence sync implementation
+   * @return An implementation of fence sync
+   */
+  EglSyncImplementation* GetSyncImplementation();
+
+private:
+  /** Undefined */
+  EglFactory(const EglFactory& rhs);
+  EglFactory& operator=(const EglFactory& rhs);
+
+private:
+  EglImplementation* mEglImplementation;
+  EglImageExtensions* mEglImageExtensions;
+  EglSyncImplementation* mEglSync;
+};
+
+}
+}
+}
+
+#endif //__DALI_INTERNAL_ADAPTOR_EGL_FACTORY_IMPL_H__
diff --git a/adaptors/common/gl/egl-image-extensions.cpp b/adaptors/common/gl/egl-image-extensions.cpp
new file mode 100644 (file)
index 0000000..06f7930
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include "egl-image-extensions.h"
+
+// EXTERNAL INCLUDES
+#if DALI_GLES_VERSION >= 30
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#else
+#include <GLES2/gl2.h>
+#endif // DALI_GLES_VERSION >= 30
+
+#include <GLES2/gl2ext.h>
+
+#include <EGL/eglext.h>
+
+#include <dali/integration-api/debug.h>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <gl/egl-implementation.h>
+
+
+namespace
+{
+// function pointers assigned in InitializeEglImageKHR
+PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = 0;
+PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = 0;
+PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = 0;
+} // unnamed namespace
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
+: mEglImplementation(eglImpl),
+  mImageKHRInitialized(false),
+  mImageKHRInitializeFailed(false)
+{
+  DALI_ASSERT_ALWAYS( eglImpl && "EGL Implementation not instantiated" );
+}
+
+EglImageExtensions::~EglImageExtensions()
+{
+}
+
+void* EglImageExtensions::CreateImageKHR(EGLClientBuffer pixmap)
+{
+  if (mImageKHRInitialized == false)
+  {
+    InitializeEglImageKHR();
+  }
+
+  if (mImageKHRInitialized == false)
+  {
+    return NULL;
+  }
+
+  // Use the EGL image extension
+  const EGLint attribs[] =
+  {
+    EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+    EGL_NONE
+  };
+
+  EGLImageKHR eglImage  = eglCreateImageKHR( mEglImplementation->GetDisplay(),
+                                             EGL_NO_CONTEXT,
+                                             EGL_NATIVE_PIXMAP_KHR,
+                                             pixmap,
+                                             attribs );
+
+  DALI_ASSERT_DEBUG( EGL_NO_IMAGE_KHR != eglImage && "X11Image::GlExtensionCreate eglCreateImageKHR failed!\n");
+  if( EGL_NO_IMAGE_KHR == eglImage )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_SUCCESS :
+      {
+        break;
+      }
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object" );
+        break;
+      }
+      case EGL_BAD_CONTEXT:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_CONTEXT: Invalid EGLContext object" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: Invalid target parameter or attribute in attrib_list" );
+        break;
+      }
+      case EGL_BAD_MATCH:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_MATCH: attrib_list does not match target" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: Previously bound off-screen, or EGLImage sibling error" );
+        break;
+      }
+      case EGL_BAD_ALLOC:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ALLOC: Insufficient memory is available" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  return (void*)eglImage;
+}
+
+void EglImageExtensions::DestroyImageKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( ! mImageKHRInitialized )
+  {
+    return;
+  }
+
+  if( eglImageKHR == NULL )
+  {
+    return;
+  }
+
+  EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+  EGLBoolean result = eglDestroyImageKHR(mEglImplementation->GetDisplay(), eglImage);
+
+  if( EGL_FALSE == result )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: eglImage is not a valid EGLImageKHR object created with respect to EGLDisplay" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: EGLImage sibling error" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+void EglImageExtensions::TargetTextureKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( eglImageKHR != NULL )
+  {
+    EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+#ifdef EGL_ERROR_CHECKING
+    GLint glError = glGetError();
+#endif
+
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
+
+#ifdef EGL_ERROR_CHECKING
+    glError = glGetError();
+    if( GL_NO_ERROR != glError )
+    {
+      DALI_LOG_ERROR(" glEGLImageTargetTexture2DOES returned error %0x04x\n", glError );
+    }
+#endif
+  }
+}
+
+void EglImageExtensions::InitializeEglImageKHR()
+{
+  // avoid trying to reload extended KHR functions, if it fails the first time
+  if( ! mImageKHRInitializeFailed )
+  {
+    eglCreateImageKHR  = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); /* parasoft-suppress MISRA2004-11_1_DMC "Using EGL defined functions." */
+    eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); /* parasoft-suppress MISRA2004-11_1_DMC "Using EGL defined functions." */
+    glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); /* parasoft-suppress MISRA2004-11_1_DMC "Using EGL defined functions." */
+  }
+
+  if (eglCreateImageKHR && eglDestroyImageKHR && glEGLImageTargetTexture2DOES)
+  {
+    mImageKHRInitialized = true;
+  }
+  else
+  {
+    mImageKHRInitializeFailed = true;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/gl/egl-image-extensions.h b/adaptors/common/gl/egl-image-extensions.h
new file mode 100644 (file)
index 0000000..4bb85c2
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H__
+#define __DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+
+#include <dali/public-api/images/pixel.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EglImplementation;
+
+/**
+ * EglImageExtensions class provides EGL image extension support
+ */
+class EglImageExtensions
+{
+public:
+  /**
+   * Constructor
+   */
+  EglImageExtensions(EglImplementation* impl);
+
+  /**
+   * Destructor
+   */
+  ~EglImageExtensions();
+
+
+public:   // EGLImageKHR extension support
+
+  /**
+   * If the EGL Image extension is available this function returns a
+   * EGLImageKHR
+   * @param pixmap The pixmap
+   * @return an object that holds a EGLImageKHR
+   */
+  void* CreateImageKHR(EGLClientBuffer pixmap);
+
+  /**
+   * If the EGL Image extension is available this function
+   * destroys the a EGLImageKHR
+   * @param eglImageKHR Object that holds a EGLImageKHR
+   */
+  void DestroyImageKHR(void* eglImageKHR);
+
+  /**
+   * defines a 2D texture
+   * @param eglImageKHR Object that holds a EGLImageKHR
+   */
+  void TargetTextureKHR(void* eglImageKHR);
+
+  /**
+   * Get the functions for using ImageKHR
+   */
+  void InitializeEglImageKHR();
+
+private:
+  EglImplementation* mEglImplementation;
+
+  bool mImageKHRInitialized;             ///< Flag for whether extended KHR functions loaded
+  bool mImageKHRInitializeFailed;        ///< Flag to avoid trying to reload extended KHR functions, if
+                                         /// it fails the first time
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H__
diff --git a/adaptors/common/gl/egl-implementation.h b/adaptors/common/gl/egl-implementation.h
new file mode 100644 (file)
index 0000000..fc39442
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef __DALI_INTERNAL_EGL_IMPLEMENTATION_H__
+#define __DALI_INTERNAL_EGL_IMPLEMENTATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <egl-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * EglImplementation class provides an EGL implementation.
+ */
+class EglImplementation : public EglInterface
+{
+public:
+  /**
+   * Constructor
+   */
+  EglImplementation();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglImplementation();
+
+public:
+
+  /**
+   * (Called from  ECoreX::RenderSurface, not RenderThread, so not in i/f, hence, not virtual)
+   * Initialize GL
+   * @param display The display
+   * @param isOwnSurface whether the surface is own or not
+   * @return true on success, false on failure
+   */
+  bool InitializeGles( EGLNativeDisplayType display, bool isOwnSurface = true );
+
+  /**
+    * Create the OpenGL context.
+    * @return true if successful
+    */
+  virtual bool CreateContext();
+
+  /**
+    * Destroy the OpenGL context.
+    */
+  void DestroyContext();
+
+  /**
+    * Destroy the OpenGL surface.
+    */
+  void DestroySurface();
+
+  /**
+   * Make the OpenGL context current
+   */
+  virtual void MakeContextCurrent();
+
+  /**
+   * clear the OpenGL context
+   */
+  void MakeContextNull();
+
+  /**
+   * Terminate GL
+   */
+  virtual void TerminateGles();
+
+  /**
+   * Checks if GL is initialised
+   * @return true if it is
+   */
+  bool IsGlesInitialized() const;
+
+  /**
+   * Performs an OpenGL swap buffers command
+   */
+  virtual void SwapBuffers();
+
+  /**
+   * Performs an OpenGL copy buffers command
+   */
+  virtual void CopyBuffers();
+
+  /**
+   * Performs an EGL wait GL command
+   */
+  virtual void WaitGL();
+
+  /**
+   * Query whether an pixmap image is y-inverted
+   * @return true if a pixmap is y-inverted, otherwise false
+   */
+  virtual bool IsPixmapYInverted();
+
+  /**
+   * Choose config of egl
+   * @param isWindowType whether the config for window or pixmap
+   * @param colorDepth Bit per pixel value (ex. 32 or 24)
+  */
+  void ChooseConfig( bool isWindowType, ColorDepth depth );
+
+  /**
+    * Create an OpenGL surface using a window
+    * @param window The window to create the surface on
+    * @param colorDepth Bit per pixel value (ex. 32 or 24)
+    * @return true on success, false on failure
+    */
+  void CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth );
+
+  /**
+   * Create the OpenGL surface using a pixmap
+   * @param pixmap The pixmap to create the surface on
+   * @param colorDepth Bit per pixel value (ex. 32 or 24)
+   * @return true on success, false on failure
+   */
+  void CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth );
+
+  /**
+   * Replaces the render surface
+   * @param[in] window, the window to create the new surface on
+   * @return true if the context was lost due to a change in display
+   *         between old surface and new surface
+   */
+  bool ReplaceSurfaceWindow( EGLNativeWindowType window );
+
+  /**
+   * Replaces the render surface
+   * @param[in] pixmap, the pixmap to create the new surface on
+   * @return true if the context was lost due to a change in x-display
+   *         between old surface and new surface
+   */
+  bool ReplaceSurfacePixmap( EGLNativePixmapType pixmap );
+
+  /**
+   * returns the display with which this object was initialized
+   * @return the EGL Display.
+   */
+  EGLDisplay GetDisplay() const;
+
+  /**
+   * Returns the EGL context
+   * @return the EGL context.
+   */
+  EGLContext GetContext() const;
+
+  /**
+   * Returns the EGL config
+   * @return the EGL config.
+   */
+  EGLConfig GetConfig() const;
+
+private:
+
+  Vector<EGLint>       mContextAttribs;
+
+  EGLNativeDisplayType mEglNativeDisplay;
+  EGLNativeWindowType  mEglNativeWindow;
+  EGLNativePixmapType  mEglNativePixmap;
+
+  EGLDisplay           mEglDisplay;
+  EGLConfig            mEglConfig;
+  EGLContext           mEglContext;
+  EGLSurface           mEglSurface;
+
+  bool                 mGlesInitialized;
+  bool                 mIsOwnSurface;
+  bool                 mContextCurrent;
+  bool                 mIsWindow;
+  ColorDepth           mColorDepth;
+
+  int                  mYInverted;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_EGL_IMPLEMENTATION_H__
diff --git a/adaptors/common/gl/egl-sync-implementation.cpp b/adaptors/common/gl/egl-sync-implementation.cpp
new file mode 100644 (file)
index 0000000..1ef1cb0
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <gl/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#ifdef _ARCH_ARM_
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/eglext.h>
+
+#endif
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <gl/egl-implementation.h>
+
+#ifdef _ARCH_ARM_
+
+// function pointers
+static PFNEGLCREATESYNCKHRPROC     eglCreateSyncKHR = NULL;
+static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = NULL;
+static PFNEGLDESTROYSYNCKHRPROC    eglDestroySyncKHR = NULL;
+
+#endif
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+#ifdef _ARCH_ARM_
+
+EglSyncObject::EglSyncObject( EglImplementation& eglSyncImpl )
+: mEglSync(NULL),
+  mEglImplementation(eglSyncImpl)
+{
+  EGLDisplay display = mEglImplementation.GetDisplay();
+  mEglSync = eglCreateSyncKHR( display, EGL_SYNC_FENCE_KHR, NULL );
+  if (mEglSync == EGL_NO_SYNC_KHR)
+  {
+    DALI_LOG_ERROR("eglCreateSyncKHR failed %#0.4x\n", eglGetError());
+    mEglSync = NULL;
+  }
+}
+
+EglSyncObject::~EglSyncObject()
+{
+  if( mEglSync != NULL )
+  {
+    eglDestroySyncKHR( mEglImplementation.GetDisplay(), mEglSync );
+    EGLint error = eglGetError();
+    if( EGL_SUCCESS != error )
+    {
+      DALI_LOG_ERROR("eglDestroySyncKHR failed %#0.4x\n", error);
+    }
+  }
+}
+
+bool EglSyncObject::IsSynced()
+{
+  bool synced = false;
+
+  if( mEglSync != NULL )
+  {
+    EGLint result = eglClientWaitSyncKHR( mEglImplementation.GetDisplay(), mEglSync, 0, 0ull );
+    EGLint error = eglGetError();
+    if( EGL_SUCCESS != error )
+    {
+      DALI_LOG_ERROR("eglClientWaitSyncKHR failed %#0.4x\n", error);
+    }
+    else if( result == EGL_CONDITION_SATISFIED_KHR )
+    {
+      synced = true;
+    }
+  }
+
+  return synced;
+}
+
+EglSyncImplementation::EglSyncImplementation()
+: mEglImplementation( NULL ),
+  mSyncInitialized( false ),
+  mSyncInitializeFailed( false )
+{
+}
+
+EglSyncImplementation::~EglSyncImplementation()
+{
+}
+
+void EglSyncImplementation::Initialize( EglImplementation* eglImpl )
+{
+  mEglImplementation = eglImpl;
+}
+
+Integration::GlSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject()
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+  if( mSyncInitialized == false )
+  {
+    InitializeEglSync();
+  }
+
+  EglSyncObject* syncObject = new EglSyncObject(*mEglImplementation);
+  mSyncObjects.PushBack( syncObject );
+  return syncObject;
+}
+
+void EglSyncImplementation::DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject )
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+
+  if( mSyncInitialized == false )
+  {
+    InitializeEglSync();
+  }
+
+  for( SyncIter iter=mSyncObjects.Begin(), end=mSyncObjects.End(); iter != end; ++iter )
+  {
+    if( *iter == syncObject )
+    {
+      mSyncObjects.Erase(iter);
+      break;
+    }
+  }
+  EglSyncObject* eglSyncObject = static_cast<EglSyncObject*>(syncObject);
+  delete eglSyncObject;
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+  if( ! mSyncInitializeFailed )
+  {
+    eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR");
+    eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC)eglGetProcAddress("eglClientWaitSyncKHR");
+    eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC)eglGetProcAddress("eglDestroySyncKHR");
+  }
+
+  if( eglCreateSyncKHR && eglClientWaitSyncKHR && eglDestroySyncKHR )
+  {
+    mSyncInitialized = true;
+  }
+  else
+  {
+    mSyncInitializeFailed = true;
+  }
+}
+
+#else
+
+EglSyncObject::EglSyncObject( EglImplementation& eglImpl )
+: mPollCounter(3),
+  mEglImplementation(eglImpl)
+{
+}
+
+EglSyncObject::~EglSyncObject()
+{
+}
+
+bool EglSyncObject::IsSynced()
+{
+  if(mPollCounter <= 0)
+  {
+    return true;
+  }
+  --mPollCounter;
+  return false;
+}
+
+EglSyncImplementation::EglSyncImplementation()
+: mEglImplementation( NULL ),
+  mSyncInitialized( false ),
+  mSyncInitializeFailed( false )
+{
+}
+
+EglSyncImplementation::~EglSyncImplementation()
+{
+}
+
+void EglSyncImplementation::Initialize( EglImplementation* eglImpl )
+{
+  mEglImplementation = eglImpl;
+}
+
+Integration::GlSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject()
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+  return new EglSyncObject(*mEglImplementation);
+}
+
+void EglSyncImplementation::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+
+  // The abstraction's virtual destructor is protected, so that Core can't delete the sync objects
+  // directly (This object also needs removing from the mSyncObject container in the ARM
+  // implementation above). We therefore need to cast to the actual implementation object first.
+  EglSyncObject* eglSyncObject = static_cast<EglSyncObject*>(syncObject);
+  delete eglSyncObject;
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+#endif
+
+} // namespace Dali
+} // namespace Internal
+} // namespace Adaptor
diff --git a/adaptors/common/gl/egl-sync-implementation.h b/adaptors/common/gl/egl-sync-implementation.h
new file mode 100644 (file)
index 0000000..616f156
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_EGL_SYNC_IMPLEMENTATION_H__
+#define __DALI_INTERNAL_ADAPTOR_EGL_SYNC_IMPLEMENTATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/integration-api/gl-sync-abstraction.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EglImplementation;
+
+class EglSyncObject : public Integration::GlSyncAbstraction::SyncObject
+{
+public:
+  /**
+   * Constructor
+   */
+  EglSyncObject( EglImplementation& eglSyncImpl );
+
+  /**
+   * Destructor
+   */
+  virtual ~EglSyncObject();
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::SyncObject::IsSynced()
+   */
+  virtual bool IsSynced();
+
+private:
+#ifdef _ARCH_ARM_
+  EGLSyncKHR mEglSync;
+#else
+  int mPollCounter; // Implementations without fence sync use a 3 frame counter
+#endif
+  EglImplementation& mEglImplementation;
+};
+
+
+/**
+ * GlSyncImplementation is a concrete implementation for GlSyncAbstraction.
+ * It provides fence syncing for resources such as FrameBuffers using EGL extensions
+ *
+ * Sync objects are created in the render thread after a render instruction
+ * has been processed (i.e. GL draw calls have completed for a given FB), and
+ * tested in the update
+ */
+class EglSyncImplementation : public Integration::GlSyncAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  EglSyncImplementation();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglSyncImplementation();
+
+  /**
+   * Initialize the sync object with the Egl implementation.
+   * @param[in] impl The EGL implementation (to access display)
+   */
+  void Initialize( EglImplementation* impl );
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::CreateSyncObject()
+   */
+  virtual SyncObject* CreateSyncObject();
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::DestroySyncObject()
+   */
+  virtual void DestroySyncObject(SyncObject* syncObject);
+
+private:
+  /**
+   * Set up the function pointers
+   */
+  void InitializeEglSync();
+
+private:
+  typedef Vector<EglSyncObject*>   SyncContainer;
+  typedef SyncContainer::Iterator  SyncIter;
+
+  EglImplementation* mEglImplementation; ///< Egl implementation (to get display)
+  bool mSyncInitialized;        ///< Flag to perform initialization on first use
+  bool mSyncInitializeFailed;   ///< Flag to avoid reloading functions if failed once
+
+  SyncContainer mSyncObjects;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_EGL_ADAPTOR_SYNC_IMPLEMENTATION_H__
diff --git a/adaptors/common/gl/gl-extensions.cpp b/adaptors/common/gl/gl-extensions.cpp
new file mode 100644 (file)
index 0000000..7ca36df
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "gl-extensions.h"
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECoreX
+{
+
+GlExtensions::GlExtensions()
+  : mInitialized( false )
+{
+}
+
+GlExtensions::~GlExtensions()
+{
+}
+
+#if DALI_GLES_VERSION < 30
+
+void GlExtensions::DiscardFrameBuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_EXT_discard_framebuffer
+  if( mGlDiscardFramebuffer )
+  {
+    mGlDiscardFramebuffer(target, numAttachments, attachments);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glDiscardFramebufferEXT extension is not available\n");
+  }
+#endif
+}
+
+void GlExtensions::GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_OES_get_program_binary
+  if (mGlGetProgramBinaryOES)
+  {
+    mGlGetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glGetProgramBinaryOES extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
+void GlExtensions::ProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_OES_get_program_binary
+  if (mGlProgramBinaryOES)
+  {
+    mGlProgramBinaryOES(program, binaryFormat, binary, length);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glProgramBinaryOES extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
+void GlExtensions::Initialize()
+{
+  mInitialized = true;
+
+#ifdef GL_EXT_discard_framebuffer
+  mGlDiscardFramebuffer = (PFNGLDISCARDFRAMEBUFFEREXTPROC) eglGetProcAddress("glDiscardFramebufferEXT");
+#endif
+
+#ifdef GL_OES_get_program_binary
+  mGlGetProgramBinaryOES = (PFNGLGETPROGRAMBINARYOESPROC) eglGetProcAddress("glGetProgramBinaryOES");
+  mGlProgramBinaryOES = (PFNGLPROGRAMBINARYOESPROC) eglGetProcAddress("glProgramBinaryOES");
+#endif
+}
+
+#endif // DALI_GLES_VERSION < 30
+
+} // namespace ECoreX
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/gl/gl-extensions.h b/adaptors/common/gl/gl-extensions.h
new file mode 100644 (file)
index 0000000..569a266
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __DALI_INTERNAL_GL_EXTENSION_H__
+#define __DALI_INTERNAL_GL_EXTENSION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+#if DALI_GLES_VERSION >= 30
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+#else
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#endif
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECoreX
+{
+
+/**
+ * GlExtensions class provides GL extensions support
+ */
+class GlExtensions
+{
+public:
+
+  /**
+   * Constructor
+   */
+  GlExtensions();
+
+  /**
+   * Destructor
+   */
+  ~GlExtensions();
+
+
+public:
+
+#if DALI_GLES_VERSION < 30
+
+  /**
+   * If the GL extension is available this function discards specified data in attachments
+   * from being copied from the target to improve performance.
+   *
+   * Usage: GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
+   *        DiscardFrameBufferEXT(GL_FRAMEBUFFER, 2, attachments);
+   *
+   * @param target is usually GL_FRAMEBUFFER
+   * @param numAttachments is the count of attachments
+   * @param attachments is a pointer to the attachments
+   */
+  void DiscardFrameBuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+
+  /**
+   * GLES extension
+   * Returns the program object's executable bytecode.
+   * @param[in] program       The program object's name/id
+   * @param[in] bufSize       The maximum number of bytes that may be written into binary
+   * @param[out] length       The actual number of bytes written into binary
+   * @param[out] binaryFormat The format of the program binary
+   * @param[out] binary       The actual program bytecode
+   */
+  void GetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+
+  /**
+   * GLES extension
+   * Loads a program object with a program binary previously returned from GetProgramBinaryOES
+   * @param[in] program       The program object's name/id
+   * @param[in] binaryFormat  The format of the program binary
+   * @param[in] binary        The program bytecode
+   * @param[in] length        The number of bytes in binary
+   */
+  void ProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+
+#endif // DALI_GLES_VERSION < 30
+
+private:
+
+  /**
+   * Lazy Initialize extensions on first use
+   */
+  void Initialize();
+
+#if DALI_GLES_VERSION < 30
+
+#ifdef GL_EXT_discard_framebuffer
+  PFNGLDISCARDFRAMEBUFFEREXTPROC mGlDiscardFramebuffer;
+#endif
+
+#ifdef GL_OES_get_program_binary
+  PFNGLGETPROGRAMBINARYOESPROC mGlGetProgramBinaryOES;
+  PFNGLPROGRAMBINARYOESPROC mGlProgramBinaryOES;
+#endif
+
+#endif // DALI_GLES_VERSION < 30
+
+  bool mInitialized;
+
+};
+
+} // namespace ECoreX
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif /* __DALI_INTERNAL_GL_EXTENSION_H__ */
diff --git a/adaptors/common/gl/gl-implementation.h b/adaptors/common/gl/gl-implementation.h
new file mode 100644 (file)
index 0000000..3bccd22
--- /dev/null
@@ -0,0 +1,1555 @@
+#ifndef __DALI_INTERNAL_GL_IMPLEMENTATION_H__
+#define __DALI_INTERNAL_GL_IMPLEMENTATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#ifndef DALI_GLES_VERSION
+#error "OpenGL ES version not specified"
+#endif
+
+#if DALI_GLES_VERSION >= 30
+#include <GLES3/gl3.h>
+#else
+#include <cstdlib>
+#include <GLES2/gl2.h>
+#endif
+
+#include <dali/integration-api/gl-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <gl/gl-extensions.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * GlImplementation is a concrete implementation for GlAbstraction.
+ * The class provides an OpenGL-ES 2.0 implementation.
+ * The class is provided when creating the Integration::Core object.
+ */
+class GlImplementation: public Dali::Integration::GlAbstraction
+{
+
+public:
+  virtual ~GlImplementation() {}
+
+  void PreRender()
+  {
+    /* Do nothing in main implementation */
+  }
+
+  void PostRender()
+  {
+    /* Do nothing in main implementation */
+  }
+
+  /* OpenGL ES 2.0 */
+
+  void ActiveTexture (GLenum texture)
+  {
+    glActiveTexture(texture);
+  }
+
+  void AttachShader (GLuint program, GLuint shader)
+  {
+    glAttachShader(program,shader);
+  }
+
+  void BindAttribLocation (GLuint program, GLuint index, const char* name)
+  {
+    glBindAttribLocation(program,index,name);
+  }
+
+  void BindBuffer (GLenum target, GLuint buffer)
+  {
+    glBindBuffer(target,buffer);
+  }
+
+  void BindFramebuffer (GLenum target, GLuint framebuffer)
+  {
+    glBindFramebuffer(target,framebuffer);
+  }
+
+  void BindRenderbuffer (GLenum target, GLuint renderbuffer)
+  {
+    glBindRenderbuffer(target,renderbuffer);
+  }
+
+  void BindTexture (GLenum target, GLuint texture)
+  {
+    glBindTexture(target,texture);
+  }
+
+  void BlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    glBlendColor(red,green,blue,alpha);
+  }
+
+  void BlendEquation ( GLenum mode )
+  {
+    glBlendEquation(mode);
+  }
+
+  void BlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha)
+  {
+    glBlendEquationSeparate(modeRGB,modeAlpha);
+  }
+
+  void BlendFunc (GLenum sfactor, GLenum dfactor)
+  {
+    glBlendFunc(sfactor,dfactor);
+  }
+
+  void BlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+  {
+    glBlendFuncSeparate(srcRGB,dstRGB,srcAlpha,dstAlpha);
+  }
+
+  void BufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+  {
+    glBufferData(target,size,data,usage);
+  }
+
+  void BufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+  {
+    glBufferSubData(target,offset,size,data);
+  }
+
+  GLenum CheckFramebufferStatus (GLenum target)
+  {
+    return glCheckFramebufferStatus(target);
+  }
+
+  void Clear (GLbitfield mask)
+  {
+    glClear(mask);
+  }
+
+  void ClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    glClearColor(red,green,blue,alpha);
+  }
+
+  void ClearDepthf (GLclampf depth)
+  {
+    glClearDepthf(depth);
+  }
+
+  void ClearStencil (GLint s)
+  {
+    glClearStencil(s);
+  }
+
+  void ColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+  {
+    glColorMask(red,green,blue,alpha);
+  }
+
+  void CompileShader (GLuint shader)
+  {
+    glCompileShader(shader);
+  }
+
+  void CompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+  {
+    glCompressedTexImage2D(target,level,internalformat,width,height,border,imageSize,data);
+  }
+
+  void CompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+  {
+    glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data);
+  }
+
+  void CopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+  {
+    glCopyTexImage2D(target,level,internalformat,x,y,width,height,border);
+  }
+
+  void CopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    glCopyTexSubImage2D(target,level,xoffset,yoffset,x,y,width,height);
+  }
+
+  GLuint CreateProgram (void)
+  {
+    return glCreateProgram();
+  }
+
+  GLuint CreateShader (GLenum type)
+  {
+    return glCreateShader(type);
+  }
+
+  void CullFace (GLenum mode)
+  {
+    glCullFace(mode);
+  }
+
+  void DeleteBuffers (GLsizei n, const GLuint* buffers)
+  {
+    glDeleteBuffers(n,buffers);
+  }
+
+  void DeleteFramebuffers (GLsizei n, const GLuint* framebuffers)
+  {
+    glDeleteFramebuffers(n,framebuffers);
+  }
+
+  void DeleteProgram (GLuint program)
+  {
+    glDeleteProgram(program);
+  }
+
+  void DeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers)
+  {
+    glDeleteRenderbuffers(n,renderbuffers);
+  }
+
+  void DeleteShader (GLuint shader)
+  {
+    glDeleteShader(shader);
+  }
+
+  void DeleteTextures (GLsizei n, const GLuint* textures)
+  {
+    glDeleteTextures(n,textures);
+  }
+
+  void DepthFunc (GLenum func)
+  {
+    glDepthFunc(func);
+  }
+
+  void DepthMask (GLboolean flag)
+  {
+    glDepthMask(flag);
+  }
+
+  void DepthRangef (GLclampf zNear, GLclampf zFar)
+  {
+    glDepthRangef(zNear,zFar);
+  }
+
+  void DetachShader (GLuint program, GLuint shader)
+  {
+    glDetachShader(program,shader);
+  }
+
+  void Disable (GLenum cap)
+  {
+    glDisable(cap);
+  }
+
+  void DisableVertexAttribArray (GLuint index)
+  {
+    glDisableVertexAttribArray(index);
+  }
+
+  void DrawArrays (GLenum mode, GLint first, GLsizei count)
+  {
+    glDrawArrays(mode,first,count);
+  }
+
+  void DrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices)
+  {
+    glDrawElements(mode,count,type,indices);
+  }
+
+  void Enable (GLenum cap)
+  {
+    glEnable(cap);
+  }
+
+  void EnableVertexAttribArray (GLuint index)
+  {
+    glEnableVertexAttribArray(index);
+  }
+
+  void Finish (void)
+  {
+    glFinish();
+  }
+
+  void Flush (void)
+  {
+    glFlush();
+  }
+
+  void FramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+  {
+    glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer);
+  }
+
+  void FramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+  {
+    glFramebufferTexture2D(target,attachment,textarget,texture,level);
+  }
+
+  void FrontFace (GLenum mode)
+  {
+    glFrontFace(mode);
+  }
+
+  void GenBuffers (GLsizei n, GLuint* buffers)
+  {
+    glGenBuffers(n,buffers);
+  }
+
+  void GenerateMipmap (GLenum target)
+  {
+    glGenerateMipmap(target);
+  }
+
+  void GenFramebuffers (GLsizei n, GLuint* framebuffers)
+  {
+    glGenFramebuffers(n,framebuffers);
+  }
+
+  void GenRenderbuffers (GLsizei n, GLuint* renderbuffers)
+  {
+    glGenRenderbuffers(n,renderbuffers);
+  }
+
+  void GenTextures (GLsizei n, GLuint* textures)
+  {
+    glGenTextures(n,textures);
+  }
+
+  void GetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+    glGetActiveAttrib(program,index,bufsize,length,size,type,name);
+  }
+
+  void GetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+    glGetActiveUniform(program,index,bufsize,length,size,type,name);
+  }
+
+  void GetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+  {
+    glGetAttachedShaders(program,maxcount,count,shaders);
+  }
+
+  int  GetAttribLocation (GLuint program, const char* name)
+  {
+    return glGetAttribLocation(program,name);
+  }
+
+  void GetBooleanv (GLenum pname, GLboolean* params)
+  {
+    glGetBooleanv(pname,params);
+  }
+
+  void GetBufferParameteriv (GLenum target, GLenum pname, GLint* params)
+  {
+    glGetBufferParameteriv(target,pname,params);
+  }
+
+  GLenum       GetError (void)
+  {
+    return glGetError();
+  }
+
+  void GetFloatv (GLenum pname, GLfloat* params)
+  {
+    glGetFloatv(pname,params);
+  }
+
+  void GetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params)
+  {
+    glGetFramebufferAttachmentParameteriv(target,attachment,pname,params);
+  }
+
+  void GetIntegerv (GLenum pname, GLint* params)
+  {
+    glGetIntegerv(pname,params);
+  }
+
+  void GetProgramiv (GLuint program, GLenum pname, GLint* params)
+  {
+    glGetProgramiv(program,pname,params);
+  }
+
+  void GetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+    glGetProgramInfoLog(program,bufsize,length,infolog);
+  }
+
+  void GetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params)
+  {
+    glGetRenderbufferParameteriv(target,pname,params);
+  }
+
+  void GetShaderiv (GLuint shader, GLenum pname, GLint* params)
+  {
+    glGetShaderiv(shader,pname,params);
+  }
+
+  void GetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+    glGetShaderInfoLog(shader,bufsize,length,infolog);
+  }
+
+  void GetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+  {
+    glGetShaderPrecisionFormat(shadertype,precisiontype,range,precision);
+  }
+
+  void GetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+  {
+    glGetShaderSource(shader,bufsize,length,source);
+  }
+
+  const GLubyte* GetString (GLenum name)
+  {
+    return glGetString(name);
+  }
+
+  void GetTexParameterfv (GLenum target, GLenum pname, GLfloat* params)
+  {
+    glGetTexParameterfv(target,pname,params);
+  }
+
+  void GetTexParameteriv (GLenum target, GLenum pname, GLint* params)
+  {
+    glGetTexParameteriv(target,pname,params);
+  }
+
+  void GetUniformfv (GLuint program, GLint location, GLfloat* params)
+  {
+    glGetUniformfv(program,location,params);
+  }
+
+  void GetUniformiv (GLuint program, GLint location, GLint* params)
+  {
+    glGetUniformiv(program,location,params);
+  }
+
+  int  GetUniformLocation (GLuint program, const char* name)
+  {
+    return glGetUniformLocation(program,name);
+  }
+
+  void GetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params)
+  {
+    glGetVertexAttribfv(index,pname,params);
+  }
+
+  void GetVertexAttribiv (GLuint index, GLenum pname, GLint* params)
+  {
+    glGetVertexAttribiv(index,pname,params);
+  }
+
+  void GetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer)
+  {
+    glGetVertexAttribPointerv(index,pname,pointer);
+  }
+
+  void Hint (GLenum target, GLenum mode)
+  {
+    glHint(target,mode);
+  }
+
+  GLboolean IsBuffer (GLuint buffer)
+  {
+    return glIsBuffer(buffer);
+  }
+
+  GLboolean IsEnabled (GLenum cap)
+  {
+    return glIsEnabled(cap);
+  }
+
+  GLboolean IsFramebuffer (GLuint framebuffer)
+  {
+    return glIsFramebuffer(framebuffer);
+  }
+
+  GLboolean IsProgram (GLuint program)
+  {
+    return glIsProgram(program);
+  }
+
+  GLboolean IsRenderbuffer (GLuint renderbuffer)
+  {
+    return glIsRenderbuffer(renderbuffer);
+  }
+
+  GLboolean IsShader (GLuint shader)
+  {
+    return glIsShader(shader);
+  }
+
+  GLboolean IsTexture (GLuint texture)
+  {
+    return glIsTexture(texture);
+  }
+
+  void LineWidth (GLfloat width)
+  {
+    glLineWidth(width);
+  }
+
+  void LinkProgram (GLuint program)
+  {
+    glLinkProgram(program);
+  }
+
+  void PixelStorei (GLenum pname, GLint param)
+  {
+    glPixelStorei(pname,param);
+  }
+
+  void PolygonOffset (GLfloat factor, GLfloat units)
+  {
+    glPolygonOffset(factor,units);
+  }
+
+  void ReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+  {
+    glReadPixels(x,y,width,height,format,type,pixels);
+  }
+
+  void ReleaseShaderCompiler (void)
+  {
+    glReleaseShaderCompiler();
+  }
+
+  void RenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+    glRenderbufferStorage(target,internalformat,width,height);
+  }
+
+  void SampleCoverage (GLclampf value, GLboolean invert)
+  {
+    glSampleCoverage(value,invert);
+  }
+
+  void Scissor (GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    glScissor(x,y,width,height);
+  }
+
+  void ShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+  {
+    glShaderBinary(n,shaders,binaryformat,binary,length);
+  }
+
+  void ShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length)
+  {
+    glShaderSource(shader,count,string,length);
+  }
+
+  void StencilFunc (GLenum func, GLint ref, GLuint mask)
+  {
+    glStencilFunc(func,ref,mask);
+  }
+
+  void StencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask)
+  {
+    glStencilFuncSeparate(face,func,ref,mask);
+  }
+
+  void StencilMask (GLuint mask)
+  {
+    glStencilMask(mask);
+  }
+
+  void StencilMaskSeparate (GLenum face, GLuint mask)
+  {
+    glStencilMaskSeparate(face,mask);
+  }
+
+  void StencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    glStencilOp(fail,zfail,zpass);
+  }
+
+  void StencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    glStencilOpSeparate(face,fail,zfail,zpass);
+  }
+
+  void TexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels)
+  {
+    glTexImage2D(target,level,internalformat,width,height,border,format,type,pixels);
+  }
+
+  void TexParameterf (GLenum target, GLenum pname, GLfloat param)
+  {
+    glTexParameterf(target,pname,param);
+  }
+
+  void TexParameterfv (GLenum target, GLenum pname, const GLfloat* params)
+  {
+    glTexParameterfv(target,pname,params);
+  }
+
+  void TexParameteri (GLenum target, GLenum pname, GLint param)
+  {
+    glTexParameteri(target,pname,param);
+  }
+
+  void TexParameteriv (GLenum target, GLenum pname, const GLint* params)
+  {
+    glTexParameteriv(target,pname,params);
+  }
+
+  void TexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+  {
+    glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels);
+  }
+
+  void Uniform1f (GLint location, GLfloat x)
+  {
+    glUniform1f(location,x);
+  }
+
+  void Uniform1fv (GLint location, GLsizei count, const GLfloat* v)
+  {
+    glUniform1fv(location,count,v);
+  }
+
+  void Uniform1i (GLint location, GLint x)
+  {
+    glUniform1i(location,x);
+  }
+
+  void Uniform1iv (GLint location, GLsizei count, const GLint* v)
+  {
+    glUniform1iv(location,count,v);
+  }
+
+  void Uniform2f (GLint location, GLfloat x, GLfloat y)
+  {
+    glUniform2f(location,x,y);
+  }
+
+  void Uniform2fv (GLint location, GLsizei count, const GLfloat* v)
+  {
+    glUniform2fv(location,count,v);
+  }
+
+  void Uniform2i (GLint location, GLint x, GLint y)
+  {
+    glUniform2i(location,x,y);
+  }
+
+  void Uniform2iv (GLint location, GLsizei count, const GLint* v)
+  {
+    glUniform2iv(location,count,v);
+  }
+
+  void Uniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z)
+  {
+    glUniform3f(location,x,y,z);
+  }
+
+  void Uniform3fv (GLint location, GLsizei count, const GLfloat* v)
+  {
+    glUniform3fv(location,count,v);
+  }
+
+  void Uniform3i (GLint location, GLint x, GLint y, GLint z)
+  {
+    glUniform3i(location,x,y,z);
+  }
+
+  void Uniform3iv (GLint location, GLsizei count, const GLint* v)
+  {
+    glUniform3iv(location,count,v);
+  }
+
+  void Uniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+    glUniform4f(location,x,y,z,w);
+  }
+
+  void Uniform4fv (GLint location, GLsizei count, const GLfloat* v)
+  {
+    glUniform4fv(location,count,v);
+  }
+
+  void Uniform4i (GLint location, GLint x, GLint y, GLint z, GLint w)
+  {
+    glUniform4i(location,x,y,z,w);
+  }
+
+  void Uniform4iv (GLint location, GLsizei count, const GLint* v)
+  {
+    glUniform4iv(location,count,v);
+  }
+
+  void UniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    glUniformMatrix2fv(location,count,transpose,value);
+  }
+
+  void UniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    glUniformMatrix3fv(location,count,transpose,value);
+  }
+
+  void UniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    glUniformMatrix4fv(location,count,transpose,value);
+  }
+
+  void UseProgram (GLuint program)
+  {
+    glUseProgram(program);
+  }
+
+  void ValidateProgram (GLuint program)
+  {
+    glValidateProgram(program);
+  }
+
+  void VertexAttrib1f (GLuint indx, GLfloat x)
+  {
+    glVertexAttrib1f(indx,x);
+  }
+
+  void VertexAttrib1fv (GLuint indx, const GLfloat* values)
+  {
+    glVertexAttrib1fv(indx,values);
+  }
+
+  void VertexAttrib2f (GLuint indx, GLfloat x, GLfloat y)
+  {
+    glVertexAttrib2f(indx,x,y);
+  }
+
+  void VertexAttrib2fv (GLuint indx, const GLfloat* values)
+  {
+    glVertexAttrib2fv(indx,values);
+  }
+
+  void VertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+  {
+    glVertexAttrib3f(indx,x,y,z);
+  }
+
+  void VertexAttrib3fv (GLuint indx, const GLfloat* values)
+  {
+    glVertexAttrib3fv(indx,values);
+  }
+
+  void VertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+    glVertexAttrib4f(indx,x,y,z,w);
+  }
+
+  void VertexAttrib4fv (GLuint indx, const GLfloat* values)
+  {
+    glVertexAttrib4fv(indx,values);
+  }
+
+  void VertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+  {
+    glVertexAttribPointer(indx,size,type,normalized,stride,ptr);
+  }
+
+  void Viewport (GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    glViewport(x,y,width,height);
+  }
+
+  /* OpenGL ES 3.0 */
+
+  void ReadBuffer(GLenum mode)
+  {
+#if DALI_GLES_VERSION >= 30
+    glReadBuffer(mode);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDrawRangeElements(mode,start,end,count,type,indices);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+#if DALI_GLES_VERSION >= 30
+    glTexImage3D(target,level,internalformat,width,height,depth,border,format,type,pixels);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+#if DALI_GLES_VERSION >= 30
+    glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+#if DALI_GLES_VERSION >= 30
+    glCopyTexSubImage3D(target,level,xoffset,yoffset,zoffset,x,y,width,height);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+  {
+#if DALI_GLES_VERSION >= 30
+    glCompressedTexImage3D(target,level,internalformat,width,height,depth,border,imageSize,data);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+  {
+#if DALI_GLES_VERSION >= 30
+    glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GenQueries(GLsizei n, GLuint* ids)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGenQueries(n,ids);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DeleteQueries(GLsizei n, const GLuint* ids)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDeleteQueries(n,ids);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean IsQuery(GLuint id)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glIsQuery(id);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BeginQuery(GLenum target, GLuint id)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBeginQuery(target,id);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void EndQuery(GLenum target)
+  {
+#if DALI_GLES_VERSION >= 30
+    glEndQuery(target);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetQueryiv(GLenum target, GLenum pname, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetQueryiv(target,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetQueryObjectuiv(id,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean UnmapBuffer(GLenum target)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glUnmapBuffer(target);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetBufferPointerv(target,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DrawBuffers(GLsizei n, const GLenum* bufs)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDrawBuffers(n,bufs);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix2x3fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix3x2fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix2x4fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix4x2fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix3x4fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformMatrix4x3fv(location,count,transpose,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBlitFramebuffer(srcX0,srcY0,srcX1,srcY1,dstX0,dstY0,dstX1,dstY1,mask,filter);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+#if DALI_GLES_VERSION >= 30
+    glRenderbufferStorageMultisample(target,samples,internalformat,width,height);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+  {
+#if DALI_GLES_VERSION >= 30
+    glFramebufferTextureLayer(target,attachment,texture,level,layer);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLvoid* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glMapBufferRange(target,offset,length,access);
+#else
+    return NULL;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+  {
+#if DALI_GLES_VERSION >= 30
+    glFlushMappedBufferRange(target,offset,length);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BindVertexArray(GLuint array)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBindVertexArray(array);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DeleteVertexArrays(GLsizei n, const GLuint* arrays)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDeleteVertexArrays(n,arrays);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GenVertexArrays(GLsizei n, GLuint* arrays)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGenVertexArrays(n,arrays);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean IsVertexArray(GLuint array)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glIsVertexArray(array);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetIntegeri_v(GLenum target, GLuint index, GLint* data)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetIntegeri_v(target,index,data);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BeginTransformFeedback(GLenum primitiveMode)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBeginTransformFeedback(primitiveMode);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void EndTransformFeedback(void)
+  {
+#if DALI_GLES_VERSION >= 30
+    glEndTransformFeedback();
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBindBufferRange(target,index,buffer,offset,size);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBindBufferBase(target,index,buffer);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode)
+  {
+#if DALI_GLES_VERSION >= 30
+    glTransformFeedbackVaryings(program,count,varyings,bufferMode);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribIPointer(index,size,type,stride,pointer);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetVertexAttribIiv(index,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetVertexAttribIuiv(index,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribI4i(index,x,y,z,w);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribI4ui(index,x,y,z,w);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribI4iv(GLuint index, const GLint* v)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribI4iv(index,v);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribI4uiv(GLuint index, const GLuint* v)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribI4uiv(index,v);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetUniformuiv(GLuint program, GLint location, GLuint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetUniformuiv(program,location,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLint GetFragDataLocation(GLuint program, const GLchar *name)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glGetFragDataLocation(program,name);
+#else
+    return -1;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform1ui(GLint location, GLuint v0)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform1ui(location,v0);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform2ui(GLint location, GLuint v0, GLuint v1)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform2ui(location,v0,v1);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform3ui(location,v0,v1,v2);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform4ui(location,v0,v1,v2,v3);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform1uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform1uiv(location,count,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform2uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform2uiv(location,count,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform3uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform3uiv(location,count,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void Uniform4uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniform4uiv(location,count,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glClearBufferiv(buffer,drawbuffer,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glClearBufferuiv(buffer,drawbuffer,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glClearBufferfv(buffer,drawbuffer,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+  {
+#if DALI_GLES_VERSION >= 30
+    glClearBufferfi(buffer,drawbuffer,depth,stencil);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  const GLubyte* GetStringi(GLenum name, GLuint index)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glGetStringi(name,index);
+#else
+    return NULL;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+  {
+#if DALI_GLES_VERSION >= 30
+    glCopyBufferSubData(readTarget,writeTarget,readOffset,writeOffset,size);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glGetUniformBlockIndex(program,uniformBlockName);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+  {
+#if DALI_GLES_VERSION >= 30
+    glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDrawArraysInstanced(mode,first,count,instanceCount);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDrawElementsInstanced(mode,count,type,indices,instanceCount);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLsync FenceSync(GLenum condition, GLbitfield flags)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glFenceSync(condition,flags);
+#else
+    return NULL;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean IsSync(GLsync sync)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glIsSync(sync);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DeleteSync(GLsync sync)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDeleteSync(sync);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glClientWaitSync(sync,flags,timeout);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+#if DALI_GLES_VERSION >= 30
+    glWaitSync(sync,flags,timeout);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetInteger64v(GLenum pname, GLint64* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetInteger64v(pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetSynciv(sync,pname,bufSize,length,values);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetInteger64i_v(GLenum target, GLuint index, GLint64* data)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetInteger64i_v(target,index,data);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetBufferParameteri64v(target,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GenSamplers(GLsizei count, GLuint* samplers)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGenSamplers(count,samplers);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DeleteSamplers(GLsizei count, const GLuint* samplers)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDeleteSamplers(count,samplers);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean IsSampler(GLuint sampler)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glIsSampler(sampler);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BindSampler(GLuint unit, GLuint sampler)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBindSampler(unit,sampler);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
+  {
+#if DALI_GLES_VERSION >= 30
+    glSamplerParameteri(sampler,pname,param);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param)
+  {
+#if DALI_GLES_VERSION >= 30
+    glSamplerParameteriv(sampler,pname,param);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
+  {
+#if DALI_GLES_VERSION >= 30
+    glSamplerParameterf(sampler,pname,param);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param)
+  {
+#if DALI_GLES_VERSION >= 30
+    glSamplerParameterfv(sampler,pname,param);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetSamplerParameteriv(sampler,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetSamplerParameterfv(sampler,pname,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void VertexAttribDivisor(GLuint index, GLuint divisor)
+  {
+#if DALI_GLES_VERSION >= 30
+    glVertexAttribDivisor(index,divisor);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void BindTransformFeedback(GLenum target, GLuint id)
+  {
+#if DALI_GLES_VERSION >= 30
+    glBindTransformFeedback(target,id);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids)
+  {
+#if DALI_GLES_VERSION >= 30
+    glDeleteTransformFeedbacks(n,ids);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GenTransformFeedbacks(GLsizei n, GLuint* ids)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGenTransformFeedbacks(n,ids);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  GLboolean IsTransformFeedback(GLuint id)
+  {
+#if DALI_GLES_VERSION >= 30
+    return glIsTransformFeedback(id);
+#else
+    return 0;
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void PauseTransformFeedback(void)
+  {
+#if DALI_GLES_VERSION >= 30
+    glPauseTransformFeedback();
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ResumeTransformFeedback(void)
+  {
+#if DALI_GLES_VERSION >= 30
+    glResumeTransformFeedback();
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)
+  {
+#if DALI_GLES_VERSION >= 30
+    // if OpenGL ES 2.0 compatibility is need this can be implemented with
+    // glGetProgramBinaryOES
+    glGetProgramBinary(program,bufSize,length,binaryFormat,binary);
+#else
+    mGlExtensions.GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length)
+  {
+#if DALI_GLES_VERSION >= 30
+    // if OpenGL ES 2.0 compatibility is need this can be implemented with
+    // glProgramBinaryOES
+    glProgramBinary(program,binaryFormat,binary,length);
+#else
+    mGlExtensions.ProgramBinaryOES(program, binaryFormat, binary, length);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void ProgramParameteri(GLuint program, GLenum pname, GLint value)
+  {
+#if DALI_GLES_VERSION >= 30
+    glProgramParameteri(program,pname,value);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
+  {
+#if DALI_GLES_VERSION >= 30
+    // if OpenGL ES 2.0 compatibility is need this can be implemented with
+    // glDiscardFramebufferEXT
+    glInvalidateFramebuffer(target,numAttachments,attachments);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+#if DALI_GLES_VERSION >= 30
+    glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+#if DALI_GLES_VERSION >= 30
+    glTexStorage2D(target,levels,internalformat,width,height);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+  {
+#if DALI_GLES_VERSION >= 30
+    glTexStorage3D(target,levels,internalformat,width,height,depth);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+  void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
+  {
+#if DALI_GLES_VERSION >= 30
+    glGetInternalformativ(target,internalformat,pname,bufSize,params);
+#endif // DALI_GLES_VERSION >= 30
+  }
+
+private:
+  ECoreX::GlExtensions mGlExtensions;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_GL_IMPLEMENTATION_H__
diff --git a/adaptors/common/gl/gl-proxy-implementation.cpp b/adaptors/common/gl/gl-proxy-implementation.cpp
new file mode 100644 (file)
index 0000000..1b62416
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "gl-proxy-implementation.h"
+
+// EXTERNAL INCLUDES
+#include <math.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <base/environment-options.h>
+
+namespace
+{
+const int NUM_FRAMES_PER_SECOND(60);
+}
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+Sampler::Sampler( const char* description )
+: mDescription( description ),
+  mAccumulated(0.0f),
+  mAccumulatedSquare(0.0f),
+  mMin(0.0f),
+  mMax(0.0f),
+  mNumSamples(0),
+  mCurrentFrameCount(0)
+{
+}
+
+void Sampler::Increment()
+{
+  mCurrentFrameCount++;
+}
+
+void Sampler::Reset()
+{
+  mAccumulated = 0.0f;
+  mAccumulatedSquare= 0.0f;
+  mMin = 0.0f;
+  mMax = 0.0f;
+  mNumSamples = 0;
+  mCurrentFrameCount = 0;
+}
+
+void Sampler::Accumulate()
+{
+  if( mNumSamples == 0 )
+  {
+    mMin = mCurrentFrameCount;
+    mMax = mCurrentFrameCount;
+  }
+  else
+  {
+    if(mCurrentFrameCount < mMin)
+    {
+      mMin = mCurrentFrameCount;
+    }
+    if(mCurrentFrameCount > mMax)
+    {
+      mMax = mCurrentFrameCount;
+    }
+  }
+
+  mNumSamples++;
+
+  mAccumulated += mCurrentFrameCount;
+  mAccumulatedSquare += (mCurrentFrameCount * mCurrentFrameCount);
+  mCurrentFrameCount = 0;
+}
+const char* Sampler::GetDescription() const
+{
+  return mDescription;
+}
+
+float Sampler::GetMeanValue() const
+{
+  float meanValue = 0;
+  if( mNumSamples > 0 )
+  {
+    meanValue = mAccumulated / (float)mNumSamples;
+  }
+  return meanValue;
+}
+
+float Sampler::GetStandardDeviation() const
+{
+  float standardDeviation=0.0f;
+  if( mNumSamples > 0 )
+  {
+    standardDeviation = sqrtf( mNumSamples * mAccumulatedSquare - (mAccumulated*mAccumulated)) / mNumSamples;
+  }
+  return standardDeviation;
+}
+
+float Sampler::GetMin() const
+{
+  return mMin;
+}
+
+float Sampler::GetMax() const
+{
+  return mMax;
+}
+
+GlProxyImplementation::GlProxyImplementation(EnvironmentOptions& environmentOptions)
+: mEnvironmentOptions(environmentOptions),
+  mActiveTextureSampler( "ActiveTexture calls"),
+  mClearSampler("Clear calls"),
+  mBindBufferSampler( "Bind buffers"),
+  mBindTextureSampler( "Bind textures"),
+  mDrawSampler("Draw calls"),
+  mUniformSampler("Uniform sets"),
+  mUseProgramSampler("Used programs"),
+  mDrawCount(0),
+  mUniformCount(0),
+  mFrameCount(0)
+{
+}
+
+GlProxyImplementation::~GlProxyImplementation()
+{
+}
+
+void GlProxyImplementation::PreRender()
+{
+}
+
+void GlProxyImplementation::PostRender( unsigned int timeDelta )
+{
+  // Accumulate counts in each sampler
+  AccumulateSamples();
+
+  // When we reach the desired frame count, output the averages from the samples
+  mFrameCount++;
+  if( mFrameCount >= mEnvironmentOptions.GetGlesCallTime() * NUM_FRAMES_PER_SECOND )
+  {
+    LogResults();
+    ResetSamplers();
+  }
+}
+
+void GlProxyImplementation::ActiveTexture( GLenum texture )
+{
+  mActiveTextureSampler.Increment();
+  GlImplementation::ActiveTexture(texture);
+}
+
+void GlProxyImplementation::Clear( GLbitfield mask )
+{
+  mClearSampler.Increment();
+  GlImplementation::Clear(mask);
+}
+
+void GlProxyImplementation::BindBuffer( GLenum target, GLuint buffer )
+{
+  mBindBufferSampler.Increment();
+  GlImplementation::BindBuffer(target,buffer);
+}
+
+void GlProxyImplementation::BindTexture( GLenum target, GLuint texture )
+{
+  mBindTextureSampler.Increment();
+  GlImplementation::BindTexture(target,texture);
+}
+
+void GlProxyImplementation::DrawArrays( GLenum mode, GLint first, GLsizei count )
+{
+  mDrawSampler.Increment();
+  GlImplementation::DrawArrays(mode,first,count);
+}
+
+void GlProxyImplementation::DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices )
+{
+  mDrawSampler.Increment();
+  GlImplementation::DrawElements(mode,count,type,indices);
+}
+
+void GlProxyImplementation::Uniform1f( GLint location, GLfloat x )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1f(location,x);
+}
+
+void GlProxyImplementation::Uniform1fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1fv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform1i( GLint location, GLint x )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1i(location,x);
+}
+
+void GlProxyImplementation::Uniform1iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1iv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform2f( GLint location, GLfloat x, GLfloat y)
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2f(location,x,y);
+}
+
+void GlProxyImplementation::Uniform2fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2fv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform2i( GLint location, GLint x, GLint y )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2i(location,x,y);
+}
+
+void GlProxyImplementation::Uniform2iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2iv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform3f( GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3f(location,x,y,z);
+}
+
+void GlProxyImplementation::Uniform3fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3fv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform3i( GLint location, GLint x, GLint y, GLint z )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3i(location,x,y,z);
+}
+
+void GlProxyImplementation::Uniform3iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3iv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform4f( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4f(location,x,y,z,w);
+}
+
+void GlProxyImplementation::Uniform4fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4fv(location,count,v);
+}
+
+void GlProxyImplementation::Uniform4i( GLint location, GLint x, GLint y, GLint z, GLint w )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4i(location,x,y,z,w);
+}
+
+void GlProxyImplementation::Uniform4iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4iv(location,count,v);
+}
+
+void GlProxyImplementation::UniformMatrix2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix2fv(location,count,transpose,value);
+}
+
+void GlProxyImplementation::UniformMatrix3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix3fv(location,count,transpose,value);
+}
+
+void GlProxyImplementation::UniformMatrix4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix4fv(location,count,transpose,value);
+}
+
+void GlProxyImplementation::UseProgram( GLuint program )
+{
+  mUseProgramSampler.Increment();
+  GlImplementation::UseProgram(program);
+}
+
+void GlProxyImplementation::AccumulateSamples()
+{
+  // Accumulate counts in each sampler
+  mActiveTextureSampler.Accumulate();
+  mClearSampler.Accumulate();
+  mBindBufferSampler.Accumulate();
+  mBindTextureSampler.Accumulate();
+  mDrawSampler.Accumulate();
+  mUniformSampler.Accumulate();
+  mUseProgramSampler.Accumulate();
+}
+
+void GlProxyImplementation::LogResults()
+{
+  Debug::LogMessage( Debug::DebugInfo, "OpenGL ES statistics sampled over %d frames) operations per frame:\n", mFrameCount );
+  LogCalls( mActiveTextureSampler );
+  LogCalls( mClearSampler );
+  LogCalls( mBindBufferSampler );
+  LogCalls( mBindTextureSampler );
+  LogCalls( mDrawSampler );
+  LogCalls( mUniformSampler );
+  LogCalls( mUseProgramSampler );
+}
+
+void GlProxyImplementation::LogCalls( const Sampler& sampler )
+{
+  Debug::LogMessage( Debug::DebugInfo, "  %s : Mean %5.2f  (Min:%5.2f, Max:%5.2f, StdDev:%5.2f)\n",
+                     sampler.GetDescription(),
+                     sampler.GetMeanValue(), sampler.GetMin(), sampler.GetMax(),
+                     sampler.GetStandardDeviation() );
+}
+
+void GlProxyImplementation::ResetSamplers()
+{
+  mActiveTextureSampler.Reset();
+  mClearSampler.Reset();
+  mBindBufferSampler.Reset();
+  mBindTextureSampler.Reset();
+  mDrawSampler.Reset();
+  mUniformSampler.Reset();
+  mUseProgramSampler.Reset();
+  mFrameCount = 0;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/gl/gl-proxy-implementation.h b/adaptors/common/gl/gl-proxy-implementation.h
new file mode 100644 (file)
index 0000000..96e8508
--- /dev/null
@@ -0,0 +1,187 @@
+#ifndef __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__
+#define __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <gl/gl-implementation.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EnvironmentOptions;
+
+/**
+ * Helper class to calculate the statistics for Open GLES calls
+ */
+class Sampler
+{
+public:
+
+  /**
+   * Constructor
+   * @param description to write to the log
+   */
+  Sampler( const char* description );
+
+  /**
+   * Increment the counter for this frame
+   */
+  void  Increment();
+
+  /**
+   * Reset the counter
+   */
+  void  Reset();
+
+  /**
+   * Accumulate the count onto statistics
+   */
+  void  Accumulate();
+
+  /**
+   * @return the description of the sampler
+   */
+  const char* GetDescription() const;
+
+  /**
+   * @return the mean value
+   */
+  float GetMeanValue() const;
+
+  /**
+   * @return the standard deviation
+   */
+  float GetStandardDeviation() const;
+
+  /**
+   * @return the minimum value
+   */
+  float GetMin() const;
+
+  /**
+   * @return the maximum value
+   */
+  float GetMax() const;
+
+private: // Data
+
+  const char* mDescription;
+  float mAccumulated;
+  float mAccumulatedSquare;
+  float mMin;
+  float mMax;
+  unsigned int mNumSamples;
+  unsigned int mCurrentFrameCount;
+};
+
+/**
+ * GlProxyImplementation is a wrapper for the concrete implementation
+ * of GlAbstraction that also gathers statistical information.
+ */
+class GlProxyImplementation : public GlImplementation
+{
+public:
+
+  /**
+   * Constructor
+   * @param environmentOptions to check how often to log results
+   */
+  GlProxyImplementation(EnvironmentOptions& environmentOptions);
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~GlProxyImplementation();
+
+  /**
+   * @copydoc GlAbstraction::PreRender();
+   */
+  virtual void PreRender();
+
+  /**
+   * @copydoc GlAbstraction::PostRender();
+   */
+  virtual void PostRender( unsigned int timeDelta );
+
+  /* OpenGL ES 2.0 API */
+  virtual void ActiveTexture(GLenum texture);
+
+  virtual void Clear( GLbitfield mask );
+
+  virtual void BindBuffer( GLenum target, GLuint buffer );
+  virtual void BindTexture( GLenum target, GLuint texture );
+
+  virtual void DrawArrays( GLenum mode, GLint first, GLsizei count );
+  virtual void DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices );
+
+  virtual void Uniform1f ( GLint location, GLfloat x );
+  virtual void Uniform1fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform1i ( GLint location, GLint x );
+  virtual void Uniform1iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform2f ( GLint location, GLfloat x, GLfloat y );
+  virtual void Uniform2fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform2i ( GLint location, GLint x, GLint y );
+  virtual void Uniform2iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform3f ( GLint location, GLfloat x, GLfloat y, GLfloat z );
+  virtual void Uniform3fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform3i ( GLint location, GLint x, GLint y, GLint z );
+  virtual void Uniform3iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform4f ( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+  virtual void Uniform4fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform4i ( GLint location, GLint x, GLint y, GLint z, GLint w );
+  virtual void Uniform4iv( GLint location, GLsizei count, const GLint* v );
+  virtual void UniformMatrix2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+  virtual void UniformMatrix3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+  virtual void UniformMatrix4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+
+  virtual void UseProgram( GLuint program );
+
+private: // Helpers
+
+  void AccumulateSamples();
+  void LogResults();
+  void LogCalls( const Sampler& sampler );
+  void ResetSamplers();
+
+private: // Data
+
+  EnvironmentOptions& mEnvironmentOptions;
+  Sampler mActiveTextureSampler;
+  Sampler mClearSampler;
+  Sampler mBindBufferSampler;
+  Sampler mBindTextureSampler;
+  Sampler mDrawSampler;
+  Sampler mUniformSampler;
+  Sampler mUseProgramSampler;
+  int mDrawCount;
+  int mUniformCount;
+  int mFrameCount;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H__
diff --git a/adaptors/common/indicator-buffer.cpp b/adaptors/common/indicator-buffer.cpp
new file mode 100644 (file)
index 0000000..bcc2c29
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "indicator-buffer.h"
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+IndicatorBuffer::IndicatorBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
+: mAdaptor(adaptor),
+  mImageWidth(width),
+  mImageHeight(height),
+  mPixelFormat(pixelFormat)
+{
+  DALI_ASSERT_ALWAYS( adaptor );
+
+  // Use BitmapImage when SharedGlBuffer extension is unavailable
+  mBitmapBuffer = new NativeBitmapBuffer( adaptor, mImageWidth, mImageHeight, mPixelFormat );
+  mNativeImage = mBitmapBuffer;
+}
+
+bool IndicatorBuffer::UpdatePixels( const unsigned char *src, size_t size )
+{
+  // Use double buffered bitmap when SharedGlBuffer extension is unavailable
+  mBitmapBuffer->Write( src, size );
+  return true;
+}
+
+NativeImageInterface& IndicatorBuffer::GetNativeImage() const
+{
+  DALI_ASSERT_DEBUG(mNativeImage.Get());
+  return *mNativeImage;
+}
+
+void IndicatorBuffer::SetAdaptor( Adaptor* adaptor )
+{
+  mAdaptor = adaptor;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/indicator-buffer.h b/adaptors/common/indicator-buffer.h
new file mode 100644 (file)
index 0000000..f32bd32
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef __DALI_INTERNAL_INDICATOR_BUFFER_H__
+#define __DALI_INTERNAL_INDICATOR_BUFFER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/ref-object.h>
+
+// INTERNAL INCLUDES
+#include <native-bitmap-buffer-impl.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeBitmapBuffer;
+class IndicatorBuffer;
+
+typedef IntrusivePtr<IndicatorBuffer> IndicatorBufferPtr;
+
+/**
+ * The IndicatorBuffer class uses the best available implementation for rendering indicator data.
+ * On platforms where EglImage is available it uses either SharedGlBuffer or NativeImageSource, on older
+ * platforms it falls back to using a bitmap buffer based solution.
+ */
+class IndicatorBuffer : public RefObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  IndicatorBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pixelFormat );
+
+  /**
+   * Copy bitmap data to pixel buffer.
+   * @param src  bitmap data source
+   * @param size size of bitmap data
+   * @return true if successful, false otherwise
+   */
+  bool UpdatePixels( const unsigned char *src, size_t size );
+
+  /**
+   * Returns the NativeImage used internally
+   * @return the NativeImage used internally
+   */
+  NativeImageInterface& GetNativeImage() const;
+
+  /**
+   * Set currently used Adaptor
+   * @param adaptor
+   */
+  void SetAdaptor( Adaptor* adaptor );
+
+private:
+  NativeImageInterfacePtr mNativeImage; ///< Image buffer created for shared file copy
+
+  NativeBitmapBufferPtr mBitmapBuffer;    ///< Image buffer created for shared file copy if extension not available
+
+  Adaptor*      mAdaptor;
+
+  int           mImageWidth;
+  int           mImageHeight;
+  Pixel::Format mPixelFormat;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_INDICATOR_H__
diff --git a/adaptors/common/indicator-impl.cpp b/adaptors/common/indicator-impl.cpp
new file mode 100644 (file)
index 0000000..e2a697f
--- /dev/null
@@ -0,0 +1,1495 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "indicator-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Evas.h>
+#include <Ecore_X.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dali/public-api/images/native-image.h>
+#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/actors/blending.h>
+#include <dali/public-api/shader-effects/shader-effect.h>
+#include <dali/public-api/images/buffer-image.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+#include <accessibility-adaptor-impl.h>
+#include <native-image-source.h>
+
+using Dali::Vector4;
+
+#if defined(DEBUG_ENABLED)
+#define STATE_DEBUG_STRING(state) (state==DISCONNECTED?"DISCONNECTED":state==CONNECTED?"CONNECTED":"UNKNOWN")
+#endif
+
+namespace
+{
+
+const float SLIDING_ANIMATION_DURATION( 0.2f ); // 200 milli seconds
+const float AUTO_INDICATOR_STAY_DURATION(3.0f); // 3 seconds
+const float SHOWING_DISTANCE_HEIGHT_RATE(0.34f); // 20 pixels
+
+enum
+{
+  KEEP_SHOWING = -1,
+  HIDE_NOW = 0
+};
+
+const int NUM_GRADIENT_INTERVALS(5); // Number of gradient intervals
+const float GRADIENT_ALPHA[NUM_GRADIENT_INTERVALS+1] = { 0.6f, 0.38f, 0.20f, 0.08f, 0.0f, 0.0f };
+
+#define MAKE_SHADER(A)#A
+
+const char* BACKGROUND_VERTEX_SHADER = MAKE_SHADER(
+  attribute mediump vec2 aPosition;
+  attribute mediump float aAlpha;
+  varying mediump float vAlpha;
+  uniform mediump mat4 uMvpMatrix;
+  uniform mediump vec3 uSize;
+
+  void main()
+  {
+    mediump vec4 vertexPosition = vec4( aPosition * uSize.xy, 0.0, 1.0 );
+    vertexPosition = uMvpMatrix * vertexPosition;
+
+    vAlpha = aAlpha;
+    gl_Position = vertexPosition;
+  }
+);
+
+const char* BACKGROUND_FRAGMENT_SHADER = MAKE_SHADER(
+  uniform lowp vec4 uColor;
+  varying mediump float vAlpha;
+
+  void main()
+  {
+    gl_FragColor = uColor;
+    gl_FragColor.a *= vAlpha;
+  }
+);
+
+
+const float OPAQUE_THRESHOLD(0.99f);
+const float TRANSPARENT_THRESHOLD(0.05f);
+
+// indicator service name
+const char* INDICATOR_SERVICE_NAME("elm_indicator");
+
+// Copied from ecore_evas_extn_engine.h
+
+enum // opcodes
+{
+   OP_RESIZE,
+   OP_SHOW,
+   OP_HIDE,
+   OP_FOCUS,
+   OP_UNFOCUS,
+   OP_UPDATE,
+   OP_UPDATE_DONE,
+   OP_SHM_REF0,
+   OP_SHM_REF1,
+   OP_SHM_REF2,
+   OP_PROFILE_CHANGE_REQUEST,
+   OP_PROFILE_CHANGE_DONE,
+   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,
+   OP_MSG_PARENT,
+   OP_MSG
+};
+
+// Copied from elm_conform.c
+
+const int MSG_DOMAIN_CONTROL_INDICATOR( 0x10001 );
+const int MSG_ID_INDICATOR_REPEAT_EVENT( 0x10002 );
+const int MSG_ID_INDICATOR_ROTATION( 0x10003 );
+const int MSG_ID_INDICATOR_OPACITY( 0X1004 );
+const int MSG_ID_INDICATOR_TYPE( 0X1005 );
+const int MSG_ID_INDICATOR_START_ANIMATION( 0X10006 );
+
+struct IpcDataUpdate
+{
+   int x, w, y, h;
+};
+
+struct IpcDataResize
+{
+  int w, h;
+};
+
+struct IpcIndicatorDataAnimation
+{
+  unsigned int xwin;
+  double       duration;
+};
+
+struct IpcDataEvMouseUp
+{
+  int               b;
+  Evas_Button_Flags flags;
+  int               mask;
+  unsigned int      timestamp;
+  Evas_Event_Flags  event_flags;
+
+  IpcDataEvMouseUp(unsigned long timestamp)
+  : b(1),
+    flags(EVAS_BUTTON_NONE),
+    mask(0),
+    timestamp(static_cast<unsigned int>(timestamp)),
+    event_flags(EVAS_EVENT_FLAG_NONE)
+  {
+  }
+};
+
+struct IpcDataEvMouseDown
+{
+  int                b;
+  Evas_Button_Flags  flags;
+  int                mask;
+  unsigned int       timestamp;
+  Evas_Event_Flags   event_flags;
+
+  IpcDataEvMouseDown(unsigned long timestamp)
+  : b(1),
+    flags(EVAS_BUTTON_NONE),
+    mask(0),
+    timestamp(static_cast<unsigned int>(timestamp)),
+    event_flags(EVAS_EVENT_FLAG_NONE)
+  {
+  }
+};
+
+struct IpcDataEvMouseMove
+{
+  int                x, y;
+  Evas_Button_Flags  flags;
+  int                mask;
+  unsigned int       timestamp;
+  Evas_Event_Flags   event_flags;
+
+  IpcDataEvMouseMove(const Dali::TouchPoint& touchPoint, unsigned long timestamp)
+  : x(static_cast<Evas_Coord>(touchPoint.local.x)),
+    y(static_cast<Evas_Coord>(touchPoint.local.y)),
+    flags(EVAS_BUTTON_NONE),
+    mask(0),
+    timestamp(static_cast<unsigned int>(timestamp)),
+    event_flags(EVAS_EVENT_FLAG_NONE)
+  {
+  }
+};
+
+struct IpcDataEvMouseOut
+{
+  unsigned int     timestamp;
+  int              mask;
+  Evas_Event_Flags event_flags;
+
+  IpcDataEvMouseOut(unsigned long timestamp)
+  : timestamp(static_cast<unsigned int>(timestamp)),
+    mask(0),
+    event_flags(EVAS_EVENT_FLAG_NONE)
+  {
+  }
+};
+
+} // anonymous namespace
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gIndicatorLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_INDICATOR");
+#endif
+
+// Impl to hide EFL implementation.
+struct Indicator::Impl
+{
+  // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  Impl(Indicator* indicator)
+  : mIndicator(indicator),
+    mEcoreEventHandler(NULL)
+  {
+    // Register Client message events for quick panel state.
+    mEcoreEventHandler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this);
+  }
+
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+    ecore_event_handler_del(mEcoreEventHandler);
+  }
+
+  /**
+   * Called when the client messages (i.e. quick panel state) are received.
+   */
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Client_Message* clientMessageEvent((Ecore_X_Event_Client_Message*)event);
+    Indicator::Impl* indicatorImpl((Indicator::Impl*)data);
+
+    if (clientMessageEvent == NULL || indicatorImpl == NULL || indicatorImpl->mIndicator == NULL)
+    {
+      return ECORE_CALLBACK_PASS_ON;
+    }
+
+    if (clientMessageEvent->message_type == ECORE_X_ATOM_E_INDICATOR_FLICK_DONE)
+    {
+      // if indicator is not showing, INDICATOR_FLICK_DONE is given
+      if( indicatorImpl->mIndicator->mVisible == Dali::Window::AUTO &&
+          !indicatorImpl->mIndicator->mIsShowing )
+      {
+        indicatorImpl->mIndicator->ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  // Data
+  Indicator*           mIndicator;
+  Ecore_Event_Handler* mEcoreEventHandler;
+};
+
+Indicator::LockFile::LockFile(const std::string filename)
+: mFilename(filename),
+  mErrorThrown(false)
+{
+  mFileDescriptor = open(filename.c_str(), O_RDWR);
+  if( mFileDescriptor == -1 )
+  {
+    mFileDescriptor = 0;
+    mErrorThrown = true;
+    DALI_LOG_ERROR( "### Cannot open %s for indicator lock ###\n", mFilename.c_str() );
+  }
+}
+
+Indicator::LockFile::~LockFile()
+{
+  // Closing file descriptor also unlocks file.
+  close( mFileDescriptor );
+}
+
+bool Indicator::LockFile::Lock()
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  bool locked = false;
+  if( mFileDescriptor > 0 )
+  {
+    if( lockf( mFileDescriptor, F_LOCK, 0 ) == 0 ) // Note, operation may block.
+    {
+      locked = true;
+    }
+    else
+    {
+      if( errno == EBADF )
+      {
+        // file descriptor is no longer valid or not writable
+        mFileDescriptor = 0;
+        mErrorThrown = true;
+        DALI_LOG_ERROR( "### Cannot lock indicator: bad file descriptor for %s ###\n", mFilename.c_str() );
+      }
+    }
+  }
+
+  return locked;
+}
+
+void Indicator::LockFile::Unlock()
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+  if( lockf( mFileDescriptor, F_ULOCK, 0 ) != 0 )
+  {
+    if( errno == EBADF )
+    {
+      // file descriptor is no longer valid or not writable
+      mFileDescriptor = 0;
+      mErrorThrown = true;
+      DALI_LOG_ERROR( "### Cannot unlock indicator: bad file descriptor for %s\n", mFilename.c_str() );
+    }
+  }
+}
+
+bool Indicator::LockFile::RetrieveAndClearErrorStatus()
+{
+  bool error = mErrorThrown;
+  mErrorThrown = false;
+  return error;
+}
+
+Indicator::ScopedLock::ScopedLock(LockFile* lockFile)
+: mLockFile(lockFile),
+  mLocked(false)
+{
+  if(mLockFile)
+  {
+    mLocked = mLockFile->Lock();
+  }
+}
+
+Indicator::ScopedLock::~ScopedLock()
+{
+  if( mLockFile )
+  {
+    mLockFile->Unlock();
+  }
+}
+
+bool Indicator::ScopedLock::IsLocked()
+{
+  return mLocked;
+}
+
+Indicator::Indicator( Adaptor* adaptor, Dali::Window::WindowOrientation orientation, Observer* observer )
+: mPixmap( 0 ),
+  mGestureDetected( false ),
+  mConnection( this ),
+  mOpacityMode( Dali::Window::OPAQUE ),
+  mState( DISCONNECTED ),
+  mAdaptor(adaptor),
+  mServerConnection( NULL ),
+  mObserver( observer ),
+  mOrientation( orientation ),
+  mImageWidth( 0 ),
+  mImageHeight( 0 ),
+  mVisible( Dali::Window::INVISIBLE ),
+  mIsShowing( true ),
+  mIsAnimationPlaying( false ),
+  mCurrentSharedFile( 0 ),
+  mImpl( NULL )
+{
+  mIndicatorImageActor = Dali::ImageActor::New();
+  mIndicatorImageActor.SetBlendFunc( Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE_MINUS_SRC_ALPHA,
+                                    Dali::BlendingFactor::ONE, Dali::BlendingFactor::ONE );
+
+  mIndicatorImageActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  mIndicatorImageActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  mIndicatorImageActor.SetSortModifier( 1.0f );
+
+  // Indicator image handles the touch event including "leave"
+  mIndicatorImageActor.SetLeaveRequired( true );
+  mIndicatorImageActor.TouchedSignal().Connect( this, &Indicator::OnTouched );
+
+  mBackgroundActor = Dali::Actor::New();
+  mBackgroundActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  mBackgroundActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  mBackgroundActor.SetColor( Color::BLACK );
+
+  mIndicatorImageContainerActor = Dali::Actor::New();
+  mIndicatorImageContainerActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  mIndicatorImageContainerActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  mIndicatorImageContainerActor.Add( mBackgroundActor );
+  mIndicatorImageContainerActor.Add( mIndicatorImageActor );
+
+  mIndicatorActor = Dali::Actor::New();
+  mIndicatorActor.Add( mIndicatorImageContainerActor );
+
+  if( mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE )
+  {
+    mBackgroundActor.SetVisible( false );
+  }
+
+  // Event handler to find out flick down gesture
+  mEventActor = Dali::Actor::New();
+  mEventActor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+  mEventActor.SetAnchorPoint( AnchorPoint::TOP_CENTER );
+  mIndicatorActor.Add( mEventActor );
+
+  // Attach pan gesture to find flick down during hiding.
+  // It can prevent the problem that scrollview gets pan gesture even indicator area is touched,
+  // since it consumes the pan gesture in advance.
+  mPanDetector = Dali::PanGestureDetector::New();
+  mPanDetector.DetectedSignal().Connect( this, &Indicator::OnPan );
+  mPanDetector.Attach( mEventActor );
+
+  Open( orientation );
+
+  // register indicator to accessibility adaptor
+  Dali::AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
+  if(accessibilityAdaptor)
+  {
+    AccessibilityAdaptor::GetImplementation( accessibilityAdaptor ).SetIndicator( this );
+  }
+  // hide the indicator by default
+  mIndicatorActor.SetVisible( false );
+
+  // create impl to handle ecore event
+  mImpl = new Impl(this);
+}
+
+Indicator::~Indicator()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+    mImpl = NULL;
+  }
+
+  if(mEventActor)
+  {
+    mEventActor.TouchedSignal().Disconnect( this, &Indicator::OnTouched );
+  }
+  Disconnect();
+}
+
+void Indicator::SetAdaptor(Adaptor* adaptor)
+{
+  mAdaptor = adaptor;
+  mIndicatorBuffer->SetAdaptor( adaptor );
+}
+
+Dali::Actor Indicator::GetActor()
+{
+  return mIndicatorActor;
+}
+
+void Indicator::Open( Dali::Window::WindowOrientation orientation )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // Calls from Window should be set up to ensure we are in a
+  // disconnected state before opening a second time.
+  DALI_ASSERT_DEBUG( mState == DISCONNECTED );
+
+  mOrientation = orientation;
+
+  Connect();
+
+  // Change background visibility depending on orientation
+  if(mOrientation == Dali::Window::LANDSCAPE || mOrientation == Dali::Window::LANDSCAPE_INVERSE  )
+  {
+    mBackgroundActor.SetVisible( false );
+  }
+  else
+  {
+    SetOpacityMode( mOpacityMode );
+  }
+}
+
+void Indicator::Close()
+{
+  DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s", STATE_DEBUG_STRING(mState) );
+
+  if( mState == CONNECTED )
+  {
+    Disconnect();
+    if( mObserver != NULL )
+    {
+      mObserver->IndicatorClosed( this );
+    }
+  }
+
+  Dali::Image emptyImage;
+  mIndicatorImageActor.SetImage(emptyImage);
+}
+
+void Indicator::SetOpacityMode( Dali::Window::IndicatorBgOpacity mode )
+{
+  mOpacityMode = mode;
+
+  //@todo replace with a gradient renderer when that is implemented
+  Dali::Geometry geometry = CreateBackgroundGeometry();
+  if( geometry )
+  {
+    mBackgroundActor.SetVisible( true );
+
+    if( mBackgroundActor.GetRendererCount() > 0 )
+    {
+      Dali::Renderer renderer = mBackgroundActor.GetRendererAt( 0 );
+      if( renderer )
+      {
+        if( renderer.GetGeometry() == geometry )
+        {
+          return;
+        }
+        else
+        {
+          renderer.SetGeometry( geometry );
+        }
+      }
+    }
+    else
+    {
+      if( !mBackgroundMaterial )
+      {
+        Dali::Shader shader = Dali::Shader::New( BACKGROUND_VERTEX_SHADER, BACKGROUND_FRAGMENT_SHADER, Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT );
+        mBackgroundMaterial = Dali::Material::New( shader );
+      }
+
+      Dali::Renderer renderer = Dali::Renderer::New( geometry, mBackgroundMaterial );
+
+      mBackgroundActor.AddRenderer( renderer );
+    }
+  }
+  else
+  {
+    mBackgroundActor.SetVisible( false );
+  }
+}
+
+void Indicator::SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate )
+{
+  if ( visibleMode != mVisible || forceUpdate )
+  {
+    // If we were previously hidden, then we should update the image data before we display the indicator
+    if ( mVisible == Dali::Window::INVISIBLE )
+    {
+      UpdateImageData( mCurrentSharedFile );
+    }
+    if ( visibleMode != Dali::Window::INVISIBLE )
+    {
+      mIndicatorActor.SetVisible( true );
+    }
+
+    mVisible = visibleMode;
+
+    if( mIndicatorImageActor.GetImage() )
+    {
+      if( CheckVisibleState() && mVisible == Dali::Window::AUTO )
+      {
+        // hide indicator
+        ShowIndicator( AUTO_INDICATOR_STAY_DURATION /* stay n sec */ );
+      }
+      else if( CheckVisibleState() && mVisible == Dali::Window::VISIBLE )
+      {
+        // show indicator
+        ShowIndicator( KEEP_SHOWING );
+      }
+      else
+      {
+        // hide indicator
+        ShowIndicator( HIDE_NOW );
+      }
+    }
+  }
+}
+
+bool Indicator::IsConnected()
+{
+  return ( mState == CONNECTED );
+}
+
+bool Indicator::SendMessage( int messageDomain, int messageId, const void *data, int size )
+{
+ if(IsConnected())
+ {
+   return mServerConnection->SendEvent( OP_MSG, messageDomain, messageId, data, size );
+ }
+ else
+ {
+   return false;
+ }
+}
+
+bool Indicator::OnTouched(Dali::Actor indicator, const Dali::TouchEvent& touchEvent)
+{
+  if( mServerConnection )
+  {
+    const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
+
+    // Send touch event to indicator server when indicator is showing
+    if( CheckVisibleState() || mIsShowing )
+    {
+      switch( touchPoint.state )
+      {
+        case Dali::TouchPoint::Down:
+        {
+          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
+          IpcDataEvMouseDown ipcDown( touchEvent.time );
+          mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
+          mServerConnection->SendEvent( OP_EV_MOUSE_DOWN, &ipcDown, sizeof(ipcDown) );
+
+          if( mVisible == Dali::Window::AUTO )
+          {
+            // Stop hiding indicator
+            ShowIndicator( KEEP_SHOWING );
+          }
+        }
+        break;
+
+        case Dali::TouchPoint::Motion:
+        {
+          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
+          mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
+        }
+        break;
+
+        case Dali::TouchPoint::Up:
+        {
+          IpcDataEvMouseUp ipcUp( touchEvent.time );
+          mServerConnection->SendEvent( OP_EV_MOUSE_UP, &ipcUp, sizeof(ipcUp) );
+
+          if( mVisible == Dali::Window::AUTO )
+          {
+            // Hide indicator
+            ShowIndicator( 0.5f /* hide after 0.5 sec */ );
+          }
+        }
+        break;
+
+        case Dali::TouchPoint::Leave:
+        {
+          IpcDataEvMouseMove ipcMove( touchPoint, touchEvent.time );
+          mServerConnection->SendEvent( OP_EV_MOUSE_MOVE, &ipcMove, sizeof(ipcMove) );
+          IpcDataEvMouseUp ipcOut( touchEvent.time );
+          mServerConnection->SendEvent( OP_EV_MOUSE_OUT, &ipcOut, sizeof(ipcOut) );
+        }
+        break;
+
+        default:
+          break;
+      }
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool Indicator::Connect()
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  DALI_ASSERT_DEBUG( mState == DISCONNECTED );
+
+  bool connected = false;
+
+  mServerConnection = new ServerConnection( INDICATOR_SERVICE_NAME, 0, false, this );
+  if( mServerConnection )
+  {
+    connected = mServerConnection->IsConnected();
+    if( ! connected )
+    {
+      delete mServerConnection;
+      mServerConnection = NULL;
+    }
+  }
+
+  if( !connected )
+  {
+    StartReconnectionTimer();
+  }
+  else
+  {
+    mState = CONNECTED;
+  }
+
+  return connected;
+}
+
+void Indicator::StartReconnectionTimer()
+{
+  if( ! mReconnectTimer )
+  {
+    mReconnectTimer = Dali::Timer::New(1000);
+    mConnection.DisconnectAll();
+    mReconnectTimer.TickSignal().Connect( mConnection, &Indicator::OnReconnectTimer );
+  }
+  mReconnectTimer.Start();
+}
+
+bool Indicator::OnReconnectTimer()
+{
+  bool retry = false;
+
+  if( mState == DISCONNECTED )
+  {
+    if( !Connect() )
+    {
+      retry = true;
+    }
+  }
+
+  return retry;
+}
+
+void Indicator::Disconnect()
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  mState = DISCONNECTED;
+
+  delete mServerConnection;
+  mServerConnection = NULL;
+
+  ClearSharedFileInfo();
+}
+
+void Indicator::Resize( int width, int height )
+{
+  if( width < 1 )
+  {
+    width = 1;
+  }
+  if( height < 1 )
+  {
+    height = 1;
+  }
+
+  if( mImageWidth != width || mImageHeight != height )
+  {
+    mImageWidth = width;
+    mImageHeight = height;
+
+    mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
+    mIndicatorActor.SetSize( mImageWidth, mImageHeight );
+    mEventActor.SetSize(mImageWidth, mImageHeight);
+    mBackgroundActor.SetSize( mImageWidth, mImageHeight );
+    mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
+  }
+}
+
+void Indicator::SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // epcEvent->ref == w
+  // epcEvent->ref_to == h
+  // epcEvent->response == buffer num
+  // epcEvent->data = lockfile + nul byte
+
+  if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) && (epcEvent->data) &&
+      (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
+  {
+    int n = epcEvent->response;
+
+    if( n >= 0 && n < SHARED_FILE_NUMBER )
+    {
+      mCurrentSharedFile = n;
+
+      mSharedFileInfo[n].mImageWidth  = epcEvent->ref;
+      mSharedFileInfo[n].mImageHeight = epcEvent->ref_to;
+
+      mSharedFileInfo[n].mLockFileName.clear();
+
+      mSharedFileInfo[n].mLockFileName = static_cast< char* >( epcEvent->data );
+
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetLockFileInfo: buffer num = %d, w = %d, h = %d, lock = %s\n",
+                     n, mSharedFileInfo[n].mImageWidth, mSharedFileInfo[n].mImageHeight, mSharedFileInfo[n].mLockFileName.c_str() );
+    }
+  }
+}
+
+void Indicator::SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // epcEvent->ref == shm id
+  // epcEvent->ref_to == shm num
+  // epcEvent->response == buffer num
+  // epcEvent->data = shm ref string + nul byte
+
+  if ( (epcEvent->data) &&
+       (epcEvent->size > 0) &&
+       (((unsigned char *)epcEvent->data)[epcEvent->size - 1] == 0) )
+  {
+    int n = epcEvent->response;
+
+    if( n >= 0 && n < SHARED_FILE_NUMBER )
+    {
+      mCurrentSharedFile = n;
+
+      mSharedFileInfo[n].mSharedFileName.clear();
+
+      mSharedFileInfo[n].mSharedFileName = static_cast< char* >( epcEvent->data );
+
+      mSharedFileInfo[n].mSharedFileID = epcEvent->ref;
+      mSharedFileInfo[n].mSharedFileNumber = epcEvent->ref_to;
+
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "SetSharedImageInfo: buffer num %d, shared file = %s, id = %d, num = %d\n",
+                     n, mSharedFileInfo[n].mSharedFileName.c_str(), mSharedFileInfo[n].mSharedFileID, mSharedFileInfo[n].mSharedFileNumber );
+    }
+  }
+}
+
+void Indicator::LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // epcEvent->ref == alpha
+  // epcEvent->ref_to == sys
+  // epcEvent->response == buffer num
+
+  int n = epcEvent->response;
+
+  if( n >= 0 && n < SHARED_FILE_NUMBER )
+  {
+    mCurrentSharedFile = n;
+
+    delete mSharedFileInfo[n].mSharedFile;
+    mSharedFileInfo[n].mSharedFile = NULL;
+
+    delete mSharedFileInfo[n].mLock;
+    mSharedFileInfo[n].mLock = NULL;
+
+    std::stringstream sharedFileID;
+    std::stringstream sharedFileNumber;
+
+    sharedFileID << mSharedFileInfo[n].mSharedFileID;
+    sharedFileNumber << mSharedFileInfo[n].mSharedFileNumber;
+
+    std::string sharedFilename = "/" + mSharedFileInfo[n].mSharedFileName + "-" + sharedFileID.str() + "." + sharedFileNumber.str();
+
+    DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "LoadSharedImage: file name = %s\n", sharedFilename.c_str() );
+
+    mSharedFileInfo[n].mSharedFile = SharedFile::New( sharedFilename.c_str(), mSharedFileInfo[n].mImageWidth * mSharedFileInfo[n].mImageWidth * 4, true );
+    if( mSharedFileInfo[n].mSharedFile != NULL )
+    {
+      mSharedFileInfo[n].mLock = new Indicator::LockFile( mSharedFileInfo[n].mLockFileName );
+      if( mSharedFileInfo[n].mLock->RetrieveAndClearErrorStatus() )
+      {
+        DALI_LOG_ERROR( "### Indicator error: Cannot open lock file %s ###\n", mSharedFileInfo[n].mLockFileName.c_str() );
+      }
+
+      CreateNewImage( n );
+
+      if( CheckVisibleState() )
+      {
+        // set default indicator type (enable the quick panel)
+        OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
+      }
+      else
+      {
+        // set default indicator type (disable the quick panel)
+        OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
+      }
+
+      SetVisible(mVisible, true);
+    }
+  }
+}
+
+void Indicator::LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // epcEvent->ref == w
+  // epcEvent->ref_to == h
+  // epcEvent->response == alpha
+  // epcEvent->data = pixmap id
+
+  if( ( epcEvent->data ) &&
+      (epcEvent->size >= (int)sizeof(PixmapId)) )
+  {
+    ClearSharedFileInfo();
+
+    if( (epcEvent->ref > 0) && (epcEvent->ref_to > 0) )
+    {
+      mImageWidth  = epcEvent->ref;
+      mImageHeight = epcEvent->ref_to;
+
+      mPixmap = *(static_cast<PixmapId*>(epcEvent->data));
+      CreateNewPixmapImage();
+
+      if( CheckVisibleState() )
+      {
+        // set default indicator type (enable the quick panel)
+        OnIndicatorTypeChanged( INDICATOR_TYPE_1 );
+      }
+      else
+      {
+        // set default indicator type (disable the quick panel)
+        OnIndicatorTypeChanged( INDICATOR_TYPE_2 );
+      }
+
+      SetVisible(mVisible, true);
+    }
+  }
+}
+
+void Indicator::UpdateImageData( int bufferNumber )
+{
+  DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "State: %s  mVisible: %s", STATE_DEBUG_STRING(mState), mVisible?"T":"F" );
+
+  if( mState == CONNECTED && mVisible )
+  {
+    if(mPixmap == 0)
+    {
+      // in case of shm indicator (not pixmap), not sure we can skip it when mIsShowing is false
+      CopyToBuffer( bufferNumber );
+    }
+    else
+    {
+      if(mIsShowing)
+      {
+        mAdaptor->RequestUpdateOnce();
+      }
+    }
+  }
+}
+
+bool Indicator::CopyToBuffer( int bufferNumber )
+{
+  bool success = false;
+
+  if( mSharedFileInfo[bufferNumber].mLock )
+  {
+    Indicator::ScopedLock scopedLock(mSharedFileInfo[bufferNumber].mLock);
+    if( mSharedFileInfo[bufferNumber].mLock->RetrieveAndClearErrorStatus() )
+    {
+      // Do nothing here.
+    }
+    else if( scopedLock.IsLocked() )
+    {
+      unsigned char *src = mSharedFileInfo[bufferNumber].mSharedFile->GetAddress();
+      size_t size = mSharedFileInfo[bufferNumber].mImageWidth * mSharedFileInfo[bufferNumber].mImageHeight * 4;
+
+      if( mIndicatorBuffer->UpdatePixels( src, size ) )
+      {
+        mAdaptor->RequestUpdateOnce();
+        success = true;
+      }
+    }
+  }
+
+  return success;
+}
+
+void Indicator::CreateNewPixmapImage()
+{
+  DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mImageWidth, mImageHeight );
+  Dali::NativeImageSourcePtr nativeImageSource = Dali::NativeImageSource::New( mPixmap );
+
+  if( nativeImageSource )
+  {
+    mIndicatorImageActor.SetImage( Dali::NativeImage::New(*nativeImageSource) );
+    mIndicatorImageActor.SetSize( mImageWidth, mImageHeight );
+    mIndicatorActor.SetSize( mImageWidth, mImageHeight );
+    mEventActor.SetSize(mImageWidth, mImageHeight);
+    mBackgroundActor.SetSize( mImageWidth, mImageHeight );
+    mIndicatorImageContainerActor.SetSize( mImageWidth, mImageHeight );
+  }
+  else
+  {
+    DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
+    Disconnect();
+    if( mObserver != NULL )
+    {
+      mObserver->IndicatorClosed( this );
+    }
+    // Don't do connection in this callback - strange things happen!
+    StartReconnectionTimer();
+  }
+}
+
+void Indicator::CreateNewImage( int bufferNumber )
+{
+  DALI_LOG_TRACE_METHOD_FMT( gIndicatorLogFilter, "W:%d H:%d", mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight );
+  mIndicatorBuffer = new IndicatorBuffer( mAdaptor, mSharedFileInfo[bufferNumber].mImageWidth, mSharedFileInfo[bufferNumber].mImageHeight, Pixel::BGRA8888 );
+  Dali::Image image = Dali::NativeImage::New( mIndicatorBuffer->GetNativeImage() );
+
+  if( CopyToBuffer( bufferNumber ) ) // Only create images if we have valid image buffer
+  {
+    mIndicatorImageActor.SetImage( image );
+  }
+  else
+  {
+    DALI_LOG_WARNING("### Cannot create indicator image - disconnecting ###\n");
+    Disconnect();
+    if( mObserver != NULL )
+    {
+      mObserver->IndicatorClosed( this );
+    }
+    // Don't do connection in this callback - strange things happen!
+    StartReconnectionTimer();
+  }
+}
+
+//@todo replace with a gradient renderer when that is implemented
+Dali::Geometry Indicator::CreateBackgroundGeometry()
+{
+  switch( mOpacityMode )
+  {
+    case Dali::Window::TRANSLUCENT:
+      if( !mTranslucentGeometry )
+      {
+        // Construct 5 interval mesh
+        // 0  +---+  1
+        //    | \ |
+        // 2  +---+  3
+        //    | \ |
+        // 4  +---+  5
+        //    | \ |
+        // 6  +---+  7
+        //    | \ |
+        // 8  +---+  9
+        //    | \ |
+        // 10 +---+  11
+
+        // Create vertices
+        struct BackgroundVertex
+        {
+          Vector2 mPosition;
+          float   mAlpha;
+        };
+
+        unsigned int numVertices = 2 * ( NUM_GRADIENT_INTERVALS + 1 );
+        BackgroundVertex vertices[ numVertices ];
+
+        float d = -0.5f;
+        float delta = 1.0f / NUM_GRADIENT_INTERVALS;
+        BackgroundVertex* currentVertex = vertices;
+        for( int y = 0; y < NUM_GRADIENT_INTERVALS + 1; ++y, d += delta )
+        {
+          currentVertex->mPosition = Vector2( -0.5f, d );
+          currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
+          currentVertex++;
+
+          currentVertex->mPosition = Vector2( 0.5f, d );
+          currentVertex->mAlpha = GRADIENT_ALPHA[ y ];
+          currentVertex++;
+        }
+
+        // Create indices
+        unsigned int numIndices = 2 * 3 * NUM_GRADIENT_INTERVALS;
+        unsigned int indices[ numIndices ];
+
+        unsigned int* currentIndex = indices;
+        for( int y = 0; y < NUM_GRADIENT_INTERVALS; ++y )
+        {
+          *currentIndex++ = (2 * y);
+          *currentIndex++ = (2 * y) + 3;
+          *currentIndex++ = (2 * y) + 1;
+
+          *currentIndex++ = (2 * y);
+          *currentIndex++ = (2 * y) + 2;
+          *currentIndex++ = (2 * y) + 3;
+        }
+
+        Dali::Property::Map vertexFormat;
+        vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
+        vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
+        Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat, numVertices );
+        vertexPropertyBuffer.SetData( vertices );
+
+        Dali::Property::Map indexFormat;
+        indexFormat[ "indices" ] = Dali::Property::INTEGER;
+        Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat, numIndices );
+        indexPropertyBuffer.SetData( indices );
+
+        // Create the geometry object
+        mTranslucentGeometry = Dali::Geometry::New();
+        mTranslucentGeometry.AddVertexBuffer( vertexPropertyBuffer );
+        mTranslucentGeometry.SetIndexBuffer( indexPropertyBuffer );
+      }
+
+      return mTranslucentGeometry;
+    case Dali::Window::OPAQUE:
+
+      if( !mSolidGeometry )
+      {
+        // Create vertices
+        struct BackgroundVertex
+        {
+          Vector2 mPosition;
+          float   mAlpha;
+        };
+
+        BackgroundVertex vertices[ 4 ] = { { Vector2( -0.5f, -0.5f ), 1.0f }, { Vector2( 0.5f, -0.5f ), 1.0f },
+                                           { Vector2( -0.5f,  0.5f ), 1.0f }, { Vector2( 0.5f,  0.5f ), 1.0f } };
+
+        // Create indices
+        unsigned int indices[ 6 ] = { 0, 3, 1, 0, 2, 3 };
+
+        Dali::Property::Map vertexFormat;
+        vertexFormat[ "aPosition" ] = Dali::Property::VECTOR2;
+        vertexFormat[ "aAlpha" ] = Dali::Property::FLOAT;
+        Dali::PropertyBuffer vertexPropertyBuffer = Dali::PropertyBuffer::New( vertexFormat, 4 );
+        vertexPropertyBuffer.SetData( vertices );
+
+        Dali::Property::Map indexFormat;
+        indexFormat[ "indices" ] = Dali::Property::INTEGER;
+        Dali::PropertyBuffer indexPropertyBuffer = Dali::PropertyBuffer::New( indexFormat, 6 );
+        indexPropertyBuffer.SetData( indices );
+
+        // Create the geometry object
+        mSolidGeometry = Dali::Geometry::New();
+        mSolidGeometry.AddVertexBuffer( vertexPropertyBuffer );
+        mSolidGeometry.SetIndexBuffer( indexPropertyBuffer );
+      }
+
+      return mSolidGeometry;
+    case Dali::Window::TRANSPARENT:
+      break;
+  }
+
+  return Dali::Geometry();
+}
+
+void Indicator::OnIndicatorTypeChanged( Type indicatorType )
+{
+  if( mObserver != NULL )
+  {
+    mObserver->IndicatorTypeChanged( indicatorType );
+  }
+}
+
+void Indicator::DataReceived( void* event )
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+  Ecore_Ipc_Event_Server_Data *epcEvent = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
+
+  switch( epcEvent->minor )
+  {
+    case OP_UPDATE:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE\n" );
+      if( mIsShowing )
+      {
+        mAdaptor->RequestUpdateOnce();
+      }
+      break;
+    }
+    case OP_UPDATE_DONE:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_UPDATE_DONE [%d]\n", epcEvent->response );
+      // epcEvent->response == display buffer #
+      UpdateImageData( epcEvent->response );
+      break;
+    }
+    case OP_SHM_REF0:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF0\n" );
+      SetSharedImageInfo( epcEvent );
+      break;
+    }
+    case OP_SHM_REF1:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF1\n" );
+      SetLockFileInfo( epcEvent );
+      break;
+    }
+    case OP_SHM_REF2:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_SHM_REF2\n" );
+      LoadSharedImage( epcEvent );
+      break;
+    }
+    case OP_RESIZE:
+    {
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_RESIZE\n" );
+
+      if( (epcEvent->data) && (epcEvent->size >= (int)sizeof(IpcDataResize)) )
+      {
+        IpcDataResize *newSize = static_cast<IpcDataResize*>( epcEvent->data );
+        Resize( newSize->w, newSize->h );
+      }
+      break;
+    }
+    case OP_MSG_PARENT:
+    {
+      int msgDomain = epcEvent->ref;
+      int msgId = epcEvent->ref_to;
+
+      void *msgData = NULL;
+      int msgDataSize = 0;
+      msgData = epcEvent->data;
+      msgDataSize = epcEvent->size;
+
+      DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT. msgDomain = %d\n", msgDomain );
+
+      if( msgDomain == MSG_DOMAIN_CONTROL_INDICATOR )
+      {
+        switch( msgId )
+        {
+          case MSG_ID_INDICATOR_TYPE:
+          {
+            DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: OP_MSG_PARENT, INDICATOR_TYPE\n" );
+            Type* indicatorType = static_cast<Type*>( epcEvent->data );
+            OnIndicatorTypeChanged( *indicatorType );
+            break;
+          }
+
+          case MSG_ID_INDICATOR_START_ANIMATION:
+          {
+            DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "Indicator client received: MSG_ID_INDICATOR_START_ANIMATION\n" );
+
+            if (msgDataSize != (int)sizeof(IpcIndicatorDataAnimation))
+            {
+              DALI_LOG_ERROR("Message data is incorrect");
+              break;
+            }
+
+            IpcIndicatorDataAnimation *animData = static_cast<IpcIndicatorDataAnimation*>(msgData);
+
+            if(!CheckVisibleState())
+            {
+              ShowIndicator( animData->duration /* n sec */ );
+            }
+            break;
+          }
+
+        }
+      }
+      break;
+    }
+  }
+}
+
+void Indicator::ConnectionClosed()
+{
+  DALI_LOG_TRACE_METHOD( gIndicatorLogFilter );
+
+  // Will get this callback if the server connection failed to start up.
+  delete mServerConnection;
+  mServerConnection = NULL;
+  mState = DISCONNECTED;
+
+  // Attempt to re-connect
+  Connect();
+}
+
+bool Indicator::CheckVisibleState()
+{
+  if( mOrientation == Dali::Window::LANDSCAPE
+    || mOrientation == Dali::Window::LANDSCAPE_INVERSE
+    || (mVisible != Dali::Window::VISIBLE) )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+void Indicator::ClearSharedFileInfo()
+{
+  for( int i = 0; i < SHARED_FILE_NUMBER; i++ )
+  {
+    delete mSharedFileInfo[i].mLock;
+    mSharedFileInfo[i].mLock = NULL;
+
+    delete mSharedFileInfo[i].mSharedFile;
+    mSharedFileInfo[i].mSharedFile = NULL;
+
+    mSharedFileInfo[i].mLockFileName.clear();
+    mSharedFileInfo[i].mSharedFileName.clear();
+  }
+}
+
+/**
+ * duration can be this
+ *
+ * enum
+ * {
+ *  KEEP_SHOWING = -1,
+ *  HIDE_NOW = 0
+ * };
+ */
+void Indicator::ShowIndicator(float duration)
+{
+  if( !mIndicatorAnimation )
+  {
+    mIndicatorAnimation = Dali::Animation::New(SLIDING_ANIMATION_DURATION);
+    mIndicatorAnimation.FinishedSignal().Connect(this, &Indicator::OnAnimationFinished);
+  }
+
+  if(mIsShowing && !EqualsZero(duration))
+  {
+    // If need to show during showing, do nothing.
+    // In 2nd phase (below) will update timer
+  }
+  else if(!mIsShowing && mIsAnimationPlaying && EqualsZero(duration))
+  {
+    // If need to hide during hiding or hidden already, do nothing
+  }
+  else
+  {
+    if( EqualsZero(duration) )
+    {
+      mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, -mImageHeight, 0), Dali::AlphaFunction::EASE_OUT );
+
+      mIsShowing = false;
+
+      OnIndicatorTypeChanged( INDICATOR_TYPE_2 ); // un-toucable
+    }
+    else
+    {
+      mIndicatorAnimation.AnimateTo( Property( mIndicatorImageContainerActor, Dali::Actor::Property::POSITION ), Vector3(0, 0, 0), Dali::AlphaFunction::EASE_OUT );
+
+      mIsShowing = true;
+
+      OnIndicatorTypeChanged( INDICATOR_TYPE_1 ); // touchable
+    }
+
+    mIndicatorAnimation.Play();
+    mIsAnimationPlaying = true;
+  }
+
+  if(duration > 0)
+  {
+    if(!mShowTimer)
+    {
+      mShowTimer = Dali::Timer::New(1000 * duration);
+      mShowTimer.TickSignal().Connect(this, &Indicator::OnShowTimer);
+    }
+    mShowTimer.SetInterval(1000* duration);
+    mShowTimer.Start();
+
+    if( mVisible == Dali::Window::AUTO )
+    {
+      // check the stage touch
+      Dali::Stage::GetCurrent().TouchedSignal().Connect( this, &Indicator::OnStageTouched );
+    }
+  }
+  else
+  {
+    if(mShowTimer && mShowTimer.IsRunning())
+    {
+      mShowTimer.Stop();
+    }
+
+    if( mVisible == Dali::Window::AUTO )
+    {
+      // check the stage touch
+      Dali::Stage::GetCurrent().TouchedSignal().Disconnect( this, &Indicator::OnStageTouched );
+    }
+  }
+}
+
+bool Indicator::OnShowTimer()
+{
+  // after time up, hide indicator
+  ShowIndicator( HIDE_NOW );
+
+  return false;
+}
+
+void Indicator::OnAnimationFinished(Dali::Animation& animation)
+{
+  mIsAnimationPlaying = false;
+  // once animation is finished and indicator is hidden, take it off stage
+  if( !mIsShowing )
+  {
+    if( mObserver != NULL )
+    {
+      mObserver->IndicatorVisibilityChanged( mIsShowing ); // is showing?
+    }
+  }
+}
+
+void Indicator::OnPan( Dali::Actor actor, const Dali::PanGesture& gesture )
+{
+  if( mServerConnection )
+  {
+    switch( gesture.state )
+    {
+      case Gesture::Started:
+      {
+        mGestureDetected = false;
+
+        // The gesture position is the current position after it has moved by the displacement.
+        // We want to reference the original position.
+        mGestureDeltaY = gesture.position.y - gesture.displacement.y;
+      }
+
+      // No break, Fall through
+      case Gesture::Continuing:
+      {
+        if( mVisible == Dali::Window::AUTO && !mIsShowing )
+        {
+          // Only take one touch point
+          if( gesture.numberOfTouches == 1 && mGestureDetected == false )
+          {
+            mGestureDeltaY += gesture.displacement.y;
+
+            if( mGestureDeltaY >= mImageHeight * SHOWING_DISTANCE_HEIGHT_RATE )
+            {
+              ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
+              mGestureDetected = true;
+            }
+          }
+        }
+
+        break;
+      }
+
+      case Gesture::Finished:
+      case Gesture::Cancelled:
+      {
+        // if indicator is showing, hide again when touching is finished (Since touch leave is activated, checking it in gesture::finish instead of touch::up)
+        if( mVisible == Dali::Window::AUTO && mIsShowing )
+        {
+          ShowIndicator( AUTO_INDICATOR_STAY_DURATION );
+        }
+        break;
+      }
+
+
+      default:
+        break;
+    }
+  }
+}
+
+void Indicator::OnStageTouched(const Dali::TouchEvent& touchEvent)
+{
+  const TouchPoint& touchPoint = touchEvent.GetPoint( 0 );
+
+  // when stage is touched while indicator is showing temporary, hide it
+  if( mIsShowing && ( CheckVisibleState() == false || mVisible == Dali::Window::AUTO ) )
+  {
+    switch( touchPoint.state )
+    {
+      case Dali::TouchPoint::Down:
+      {
+        ShowIndicator( HIDE_NOW );
+        break;
+      }
+
+      default:
+      break;
+    }
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/indicator-impl.h b/adaptors/common/indicator-impl.h
new file mode 100644 (file)
index 0000000..6c93f57
--- /dev/null
@@ -0,0 +1,475 @@
+#ifndef __DALI_INTERNAL_INDICATOR_H__
+#define __DALI_INTERNAL_INDICATOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/actors/image-actor.h>
+#include <dali/public-api/animation/animation.h>
+#include <dali/public-api/events/pan-gesture.h>
+#include <dali/public-api/events/pan-gesture-detector.h>
+#include <dali/devel-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <indicator-buffer.h>
+#include <server-connection.h>
+#include <shared-file.h>
+#include <timer.h>
+#include <window.h>
+
+namespace Dali
+{
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Adaptor;
+
+typedef unsigned int PixmapId;
+
+/**
+ * The Indicator class connects to the indicator server, and gets and draws the indicator
+ * for the given orientation.
+ */
+class Indicator : public ConnectionTracker, public ServerConnection::Observer
+{
+public:
+  enum State
+  {
+    DISCONNECTED,
+    CONNECTED
+  };
+
+  enum Type
+  {
+    INDICATOR_TYPE_UNKNOWN,
+    INDICATOR_TYPE_1,
+    INDICATOR_TYPE_2
+  };
+
+public:
+  class Observer
+  {
+  public:
+    /**
+     * Notify the observer if the indicator type changes
+     * @param[in] type The new indicator type
+     */
+    virtual void IndicatorTypeChanged( Type type ) = 0;
+
+    /**
+     * Notify the observer when the upload has completed.
+     * @param[in] indicator The indicator that has finished uploading.
+     */
+    virtual void IndicatorClosed(Indicator* indicator) = 0;
+
+    /**
+     * Notify the observer when the indicator visible status is changed.
+     * @param[in] isShowing Whether the indicator is visible.
+     */
+    virtual void IndicatorVisibilityChanged( bool isVisible ) = 0;
+  };
+
+protected:
+  /**
+   * Class to encapsulate lock file
+   */
+  class LockFile
+  {
+  public:
+    /**
+     * Constructor. open lock file
+     */
+    LockFile(const std::string filename);
+
+    /**
+     * Close lock file
+     */
+    ~LockFile();
+
+    /**
+     * Grab an exclusive lock on this file
+     * @return true if the lock succeeded, false if it failed
+     */
+    bool Lock();
+
+    /**
+     * Remove the lock
+     */
+    void Unlock();
+
+    /**
+     * Test if there is an error with the lock file, and clears
+     * the error flag;
+     * @return true if an error was thrown
+     */
+    bool RetrieveAndClearErrorStatus();
+
+  private:
+    std::string mFilename;
+    int         mFileDescriptor;
+    bool        mErrorThrown;
+  };
+
+  /**
+   * Class to ensure lock/unlock through object destruction
+   */
+  class ScopedLock
+  {
+  public:
+    /**
+     * Constructor - creates a lock on the lockfile
+     * @param[in] lockFile The lockfile to use
+     */
+    ScopedLock( LockFile* lockFile );
+
+    /**
+     * Destructor - removes the lock (if any) on the lockfile
+     */
+    ~ScopedLock();
+
+    /**
+     * Method to test if the locking succeeded
+     * @return TRUE if locked
+     */
+    bool IsLocked();
+
+  private:
+    LockFile* mLockFile; ///< The lock file to use
+    bool      mLocked;   ///< Whether the lock succeeded
+  };
+
+
+public:
+  /**
+   * Constructor. Creates a new indicator and opens a connection for
+   * the required orientation.
+   * @param[in] orientation The orientation in which to draw the indicator
+   * @param[in] observer The indicator closed
+   */
+  Indicator( Adaptor* adaptor,
+             Dali::Window::WindowOrientation orientation,
+             Observer* observer );
+
+  /**
+   * Destructor
+   */
+  virtual ~Indicator();
+
+  void SetAdaptor(Adaptor* adaptor);
+
+  /**
+   * Get the actor which contains the indicator image. Ensure that the handle is
+   * released when no longer needed.
+   * Changes from the indicator service will modify the image and resize the actor appropriately.
+   * @return The indicator actor.
+   */
+  Dali::Actor GetActor();
+
+  /**
+   * Opens a new connection for the required orientation.
+   * @param[in] orientation The new orientation
+   */
+  void Open( Dali::Window::WindowOrientation orientation );
+
+  /**
+   * Close the current connection. Will respond with Observer::IndicatorClosed()
+   * when done.
+   * @note, IndicatorClosed() will be called synchronously if there's no update
+   * in progress, or asychronously if waiting for SignalUploaded )
+   */
+  void Close();
+
+  /**
+   * Set the opacity mode of the indicator background.
+   * @param[in] mode opacity mode
+   */
+  void SetOpacityMode( Dali::Window::IndicatorBgOpacity mode );
+
+  /**
+   * Set whether the indicator is visible or not.
+   * @param[in] visibleMode visible mode for indicator bar.
+   * @param[in] forceUpdate true if want to change visible mode forcely
+   */
+  void SetVisible( Dali::Window::IndicatorVisibleMode visibleMode, bool forceUpdate = false );
+
+  /**
+   * Check whether the indicator is connected to the indicator service.
+   * @return whether the indicator is connected or not.
+   */
+  bool IsConnected();
+
+  /**
+   * Send message to the indicator service.
+   * @param[in] messageDomain Message Reference number
+   * @param[in] messageId Reference number of the message this message refers to
+   * @param[in] data The data to send as part of the message
+   * @param[in] size Length of the data, in bytes, to send
+   * @return whether the message is sent successfully or not
+   */
+  bool SendMessage( int messageDomain, int messageId, const void *data, int size );
+
+private:
+  /**
+   * Initialize the indicator actors
+   */
+  void Initialize();
+
+  /**
+   * Constructs the renderers used for the background
+   */
+  Dali::Geometry CreateBackgroundGeometry();
+
+  /**
+   * Touch event callback.
+   * It should pass the valid touch event to indicator server
+   *
+   * @param[in] indicator  The indicator actor that was touched
+   * @param[in] touchEvent The touch event
+   */
+  bool OnTouched(Dali::Actor indicator, const TouchEvent& touchEvent);
+
+  /**
+   * Pan gesture callback.
+   * It finds flick down gesture to show hidden indicator image
+   *
+   * @param[in] actor  The actor for gesture
+   * @param[in] gesture The gesture event
+   */
+  void OnPan( Dali::Actor actor, const Dali::PanGesture& gesture );
+
+  /**
+   * Touch event callback on stage.
+   * If stage is touched, hide showing indicator image
+   *
+   * @param[in] touchEvent The touch event
+   */
+  void OnStageTouched(const Dali::TouchEvent& touchEvent);
+
+  /**
+   * Connect to the indicator service
+   */
+  bool Connect();
+
+  /**
+   * Start the reconnection timer. This will run every second until we reconnect to
+   * the indicator service.
+   */
+  void StartReconnectionTimer();
+
+  /**
+   * If connection failed, attempt to re-connect every second
+   */
+  bool OnReconnectTimer();
+
+  /**
+   * Disconnect from the indicator service
+   */
+  void Disconnect();
+
+  /**
+   * Handle Resize event
+   * @param[in] width The new width
+   * @param[in] height The new height
+   */
+  void Resize( int width, int height );
+
+  /**
+   * Set the lock file info.
+   * @param[in] epcEvent Current ecore event.
+   */
+  void SetLockFileInfo( Ecore_Ipc_Event_Server_Data *epcEvent );
+
+  /**
+   * Set the shared indicator image info
+   * @param[in] epcEvent The event containing the image data
+   */
+  void SetSharedImageInfo( Ecore_Ipc_Event_Server_Data *epcEvent );
+
+  /**
+   * Load the shared indicator image
+   * @param[in] epcEvent The event containing the image data
+   */
+  void LoadSharedImage( Ecore_Ipc_Event_Server_Data *epcEvent );
+
+  /**
+   * Load the pixmap indicator image
+   * @param[in] epcEvent The event containing the image data
+   */
+  void LoadPixmapImage( Ecore_Ipc_Event_Server_Data *epcEvent );
+
+  /**
+   * Inform dali that the indicator data has been updated.
+   * @param[in] bufferNumber The shared file number
+   */
+  void UpdateImageData( int bufferNumber );
+
+  /**
+   * Lock the temporary file, Copy the shared image into IndicatorBuffer
+   * and then unlock the temporary file.
+   * Caller should ensure we are not writing image to gl texture.
+   * @param[in] bufferNumber The shared file number
+   */
+  bool CopyToBuffer( int bufferNumber );
+
+  /**
+   * Create a new image for the indicator, and set up signal handling for it.
+   * @param[in] bufferNumber The shared file number
+   */
+  void CreateNewImage( int bufferNumber );
+
+  /**
+   * Create a new pixmap image for the indicator, and set up signal handling for it.
+   */
+  void CreateNewPixmapImage();
+
+  /**
+   * Indicator type has changed.
+   * Inform observer
+   * @param[in] type The new indicator type
+   */
+  void OnIndicatorTypeChanged( Type type );
+
+  /**
+   * Check whether the indicator could be visible or invisible
+   * @return true if indicator should be shown
+   */
+  bool CheckVisibleState();
+
+  /**
+   * Show/Hide indicator actor with effect
+   * @param[in] duration how long need to show the indicator,
+   *                     if it equal to 0, hide the indicator
+   *                     if it less than 0, show always
+   */
+  void ShowIndicator( float duration );
+
+  /**
+   * Showing timer callback
+   */
+  bool OnShowTimer();
+
+  /**
+   * Showing animation finished callback
+   * @param[in] animation
+   */
+  void OnAnimationFinished( Dali::Animation& animation );
+
+private: // Implementation of ServerConnection::Observer
+  /**
+   * @copydoc Dali::Internal::Adaptor::ServerConnection::Observer::DataReceived()
+   */
+  virtual void DataReceived( void* event );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::ServerConnection::Observer::DataReceived()
+   */
+  virtual void ConnectionClosed();
+
+private:
+
+  /**
+   * Clear shared file info
+   */
+  void ClearSharedFileInfo();
+
+private:
+
+  struct SharedFileInfo
+  {
+    SharedFileInfo()
+      : mLock( NULL ),
+        mSharedFile( NULL ),
+        mImageWidth( 0 ),
+        mImageHeight( 0 ),
+        mLockFileName(),
+        mSharedFileName(),
+        mSharedFileID( 0 ),
+        mSharedFileNumber( 0 )
+    {
+    }
+
+    LockFile*                        mLock;              ///< File lock for the shared file
+    SharedFile*                      mSharedFile;        ///< Shared file
+
+    int                              mImageWidth;        ///< Shared image width
+    int                              mImageHeight;       ///< Shared image height
+
+    std::string                      mLockFileName;      ///< Lock file name
+    std::string                      mSharedFileName;    ///< Shared file name
+    int                              mSharedFileID;      ///< Shared file ID
+    int                              mSharedFileNumber;  ///< Shared file number
+  };
+
+  static const int SHARED_FILE_NUMBER = 2;               ///< Shared file number
+
+  Dali::Geometry                   mTranslucentGeometry; ///< Geometry used for rendering the translucent background
+  Dali::Geometry                   mSolidGeometry;       ///< Geometry used for rendering the opaque background
+  Dali::Material                   mBackgroundMaterial;  ///< Material used for rendering the background
+
+  IndicatorBufferPtr               mIndicatorBuffer;     ///< class which handles indicator rendering
+  PixmapId                         mPixmap;              ///< Pixmap including indicator content
+  Dali::Image                      mImage;               ///< Image created from mIndicatorBuffer
+  Dali::ImageActor                 mIndicatorImageActor; ///< Actor created from mImage
+
+  Dali::Actor                      mIndicatorImageContainerActor; ///< Actor container for image and background
+  Dali::Actor                      mBackgroundActor;     ///< Actor for background
+  Dali::Actor                      mIndicatorActor;      ///< Handle to topmost indicator actor
+  Dali::Actor                      mEventActor;          ///< Handle to event
+  Dali::PanGestureDetector         mPanDetector;         ///< Pan detector to find flick gesture for hidden indicator
+  float                            mGestureDeltaY;       ///< Checking how much panning moved
+  bool                             mGestureDetected;     ///< Whether find the flick gesture
+
+  Dali::Timer                      mReconnectTimer;      ///< Reconnection timer
+  SlotDelegate< Indicator >        mConnection;
+
+  Dali::Window::IndicatorBgOpacity mOpacityMode;         ///< Opacity enum for background
+  Indicator::State                 mState;               ///< The connection state
+
+  Adaptor*                         mAdaptor;
+  ServerConnection*                mServerConnection;
+  Indicator::Observer*             mObserver;            ///< Upload observer
+
+  Dali::Window::WindowOrientation  mOrientation;
+  int                              mImageWidth;
+  int                              mImageHeight;
+  Dali::Window::IndicatorVisibleMode mVisible;           ///< Whether the indicator is visible
+
+  Dali::Timer                      mShowTimer;           ///< Timer to show indicator
+  bool                             mIsShowing;           ///< Whether the indicator is showing on the screen
+  Dali::Animation                  mIndicatorAnimation;  ///< Animation to show/hide indicator image
+
+  bool                             mIsAnimationPlaying;  ///< Whether the animation is playing
+
+  int                              mCurrentSharedFile;   ///< Current shared file number
+  SharedFileInfo                   mSharedFileInfo[SHARED_FILE_NUMBER];    ///< Table to store shared file info
+
+  struct Impl; ///< Contains Ecore specific information
+  Impl* mImpl; ///< Created on construction and destroyed on destruction.
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif
diff --git a/adaptors/common/kernel-trace.cpp b/adaptors/common/kernel-trace.cpp
new file mode 100644 (file)
index 0000000..e654fc8
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "kernel-trace.h"
+
+// EXTERNAL HEADERS
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* TRACE_MARKER_FILE = "/sys/kernel/debug/tracing/trace_marker";
+const char* SPI_PREFIX = "SPI_EV_DALI_"; ///< prefix to let the SPI tool know it should read the trace
+}// un-named name space
+
+KernelTrace::KernelTrace()
+: mFileDescriptor( 0 ),
+  mLoggedError( false )
+{
+}
+
+KernelTrace::~KernelTrace()
+{
+  if( mFileDescriptor )
+  {
+    close( mFileDescriptor );
+  }
+}
+
+// If this function doesn't appear to work, you can test manually on the device.
+// $ cd /sys/kernel/debug/tracing
+//
+// If the folder doesn't exist then the kernel needs to be re-built with ftrace enabled
+// If it does exist, then you can continue to test ftrace is working:
+//
+// $ echo 1 > tracing_enabled
+// $ echo "test" > trace_marker
+// $ cat trace
+// should print out test message
+// If the message did not get added to the trace, then check you have write permissions to the trace_marker file.
+//
+//
+void KernelTrace::Trace( const PerformanceMarker& marker, const std::string& traceMessage )
+{
+  // Open the trace_marker file
+  if( mFileDescriptor == 0 )
+  {
+    mFileDescriptor = open( TRACE_MARKER_FILE , O_WRONLY);
+    if( mFileDescriptor == -1 )
+    {
+      // we want to keep trying to open it, so it will start working if someone fixes
+      // the permissions on the trace marker
+      mFileDescriptor = 0;
+
+      // first time we fail to open the file, log an error
+      if( !mLoggedError )
+      {
+        mLoggedError = true;
+        DALI_LOG_ERROR("Failed to open /sys/kernel/debug/tracing/trace_marker for writing please check file permissions.");
+      }
+
+    }
+  }
+
+  if( mFileDescriptor > 0 )
+  {
+      std::string msg( SPI_PREFIX );
+      msg+=traceMessage;
+
+      int ret = write( mFileDescriptor, msg.c_str(), msg.length() );
+          // if it failed then close the file description and try again next time we trace
+      if( ret < 0 )
+      {
+        close( mFileDescriptor );
+        mFileDescriptor = 0;
+      }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
diff --git a/adaptors/common/kernel-trace.h b/adaptors/common/kernel-trace.h
new file mode 100644 (file)
index 0000000..89722c5
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H__
+#define __DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <base/interfaces/trace-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Concrete Kernel Tracing Interface.
+ * Used to log trace messages to the kernel using ftrace.
+ *
+ */
+class KernelTrace : public TraceInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  KernelTrace();
+
+  /**
+   * Destructor
+   */
+  virtual ~KernelTrace();
+
+  /**
+   * @copydoc KernelTracerInterface::KernelTrace()
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage );
+
+private:
+
+  int mFileDescriptor;
+  bool mLoggedError:1;
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H__
diff --git a/adaptors/common/key-impl.cpp b/adaptors/common/key-impl.cpp
new file mode 100644 (file)
index 0000000..285a94e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "key-impl.h"
+
+// EXTERNAL INCLUDES
+#include <map>
+#include <string.h>
+#include <iostream>
+
+#include <dali/integration-api/debug.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+namespace
+{
+
+class KeyMap
+{
+  public:
+
+  KeyMap():
+  mLookup( cmpString )
+  {
+    // create the lookup
+    for( size_t i = 0; i < KEY_LOOKUP_COUNT ; ++i )
+    {
+      const KeyLookup&  keyLookup( KeyLookupTable[i] );
+      mLookup[ keyLookup.keyName  ] = DaliKeyType( keyLookup.daliKeyCode, keyLookup.deviceButton );
+    }
+  }
+
+  int GetDaliKeyEnum( const char* keyName ) const
+  {
+    Lookup::const_iterator i = mLookup.find( keyName );
+    if( i == mLookup.end() )
+    {
+      return -1;
+    }
+    else
+    {
+      return (*i).second.first;
+    }
+  }
+
+  const char* GetKeyName( int daliKeyCode ) const
+  {
+    for( size_t i = 0; i < KEY_LOOKUP_COUNT ; ++i )
+    {
+      const KeyLookup& keyLookup( KeyLookupTable[i] );
+      if( keyLookup.daliKeyCode == daliKeyCode )
+      {
+        return keyLookup.keyName;
+      }
+    }
+    return NULL;
+  }
+
+  bool IsDeviceButton( const char* keyName ) const
+  {
+    Lookup::const_iterator i = mLookup.find( keyName );
+    if ( i != mLookup.end() )
+    {
+      return (*i).second.second;
+    }
+    return false;
+  }
+
+  private:
+
+  /**
+   * compare function, to compare string by pointer
+   */
+  static bool cmpString( const char* a, const char* b)
+  {
+    return strcmp(a, b) < 0;
+  }
+
+  typedef std::pair< int, bool > DaliKeyType;
+  typedef std::map<const char* /* key name */, DaliKeyType /* key code */, bool(*) ( char const* a, char const* b) > Lookup;
+  Lookup mLookup;
+
+};
+const KeyMap globalKeyLookup;
+
+} // un-named name space
+
+bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey)
+{
+  int key = globalKeyLookup.GetDaliKeyEnum( keyEvent.keyPressedName.c_str() );
+  return daliKey == key;
+}
+
+bool IsDeviceButton( const char* keyName )
+{
+  return globalKeyLookup.IsDeviceButton( keyName );
+}
+
+const char* GetKeyName( Dali::KEY daliKey )
+{
+  return globalKeyLookup.GetKeyName( daliKey );
+}
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/key-impl.h b/adaptors/common/key-impl.h
new file mode 100644 (file)
index 0000000..15d123d
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef __DALI_KEY_IMPL_H__
+#define __DALI_KEY_IMPL_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <key.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Key matching
+ */
+namespace KeyLookup
+{
+
+struct KeyLookup
+{
+  const char* keyName;          ///< XF86 key name
+  const Dali::KEY daliKeyCode;  ///< Dali key code
+  const bool  deviceButton;     ///< Whether the key is from a button on the device
+};
+
+extern KeyLookup KeyLookupTable[];
+extern const std::size_t KEY_LOOKUP_COUNT;
+
+/**
+ * @copydoc Dali::IsKey()
+ */
+bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey );
+
+/**
+ * Check if a the given key name string is a button on the device itself.
+ * @param keyName A pointer to the key name
+ * @return true if the key is matched, false if not
+ */
+bool IsDeviceButton( const char* keyName );
+
+/**
+ * Get a key name from a dali key code.
+ * @param daliKey The dali key code
+ * @return The key name. NULL if the daliKey does not exist in the supported key lookup table.
+ */
+const char* GetKeyName( Dali::KEY daliKey );
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_KEY_IMPL_H__
diff --git a/adaptors/common/lifecycle-controller-impl.cpp b/adaptors/common/lifecycle-controller-impl.cpp
new file mode 100644 (file)
index 0000000..52b6c13
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "lifecycle-controller-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  BaseHandle handle( LifecycleController::Get() );
+
+  if ( !handle && Adaptor::IsAvailable() )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Dali::LifecycleController lifecycleController = Dali::LifecycleController( new LifecycleController() );
+      service.Register( typeid( lifecycleController ), lifecycleController );
+      handle = lifecycleController;
+    }
+  }
+
+  return handle;
+}
+TypeRegistration LIFECYCLE_CONTROLLER_TYPE( typeid(Dali::LifecycleController), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Dali::LifecycleController LifecycleController::Get()
+{
+  Dali::LifecycleController lifecycleController;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::LifecycleController ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      lifecycleController = Dali::LifecycleController( dynamic_cast< LifecycleController* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      lifecycleController = Dali::LifecycleController( new LifecycleController() );
+      service.Register( typeid( lifecycleController ), lifecycleController );
+    }
+  }
+
+  return lifecycleController;
+}
+
+LifecycleController::LifecycleController()
+{
+}
+
+LifecycleController::~LifecycleController()
+{
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  return mInitSignal;
+}
+
+void LifecycleController::EmitInitSignal()
+{
+  if( !mInitSignal.Empty() )
+  {
+    mInitSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::TerminateSignal()
+{
+  return mTerminateSignal;
+}
+
+void LifecycleController::EmitTerminateSignal()
+{
+  if( !mTerminateSignal.Empty() )
+  {
+    mTerminateSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::PauseSignal()
+{
+  return mPauseSignal;
+}
+
+void LifecycleController::EmitPauseSignal()
+{
+  if( !mPauseSignal.Empty() )
+  {
+    mPauseSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResumeSignal()
+{
+  return mResumeSignal;
+}
+
+void LifecycleController::EmitResumeSignal()
+{
+  if( !mResumeSignal.Empty() )
+  {
+    mResumeSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResetSignal()
+{
+  return mResetSignal;
+}
+
+void LifecycleController::EmitResetSignal()
+{
+  if( !mResetSignal.Empty() )
+  {
+    mResetSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResizeSignal()
+{
+  return mResizeSignal;
+}
+
+void LifecycleController::EmitResizeSignal()
+{
+  if( !mResizeSignal.Empty() )
+  {
+    mResizeSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::LanguageChangedSignal()
+{
+  return mLanguageChangedSignal;
+}
+
+void LifecycleController::EmitLanguageChangedSignal()
+{
+  if( !mLanguageChangedSignal.Empty() )
+  {
+    mLanguageChangedSignal.Emit();
+  }
+}
+
+void LifecycleController::OnInit( Dali::Application& app )
+{
+  EmitInitSignal();
+}
+
+void LifecycleController::OnTerminate( Dali::Application& app )
+{
+  EmitTerminateSignal();
+}
+
+void LifecycleController::OnPause( Dali::Application& app )
+{
+  EmitPauseSignal();
+}
+
+void LifecycleController::OnResume( Dali::Application& app )
+{
+  EmitResumeSignal();
+}
+
+void LifecycleController::OnReset( Dali::Application& app )
+{
+  EmitResetSignal();
+}
+
+void LifecycleController::OnLanguageChanged( Dali::Application& app )
+{
+  EmitLanguageChangedSignal();
+}
+
+void LifecycleController::OnResize( Dali::Application& app )
+{
+  EmitResizeSignal();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/lifecycle-controller-impl.h b/adaptors/common/lifecycle-controller-impl.h
new file mode 100644 (file)
index 0000000..486a8ed
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef __DALI_INTERNAL_LIFECYCLE_CONTROLLER_H__
+#define __DALI_INTERNAL_LIFECYCLE_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <lifecycle-controller.h>
+#include <application.h>
+
+namespace Dali
+{
+
+class Adaptor;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This provides signals that are emitted according the lifecylce of the program.
+ */
+class LifecycleController : public BaseObject, public ConnectionTracker
+{
+public:
+
+  // Creation & Destruction
+
+  /**
+   * Constructor.
+   */
+  LifecycleController();
+
+  /**
+   * Retrieve the initialized instance of the LifecycleController.
+   * @return Handle to LifecycleController.
+   */
+  static Dali::LifecycleController Get();
+
+  // Signals
+
+  /**
+   * @copydoc Dali::StyleMonitor::InitSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& InitSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::TerminateSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& TerminateSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::PauseSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& PauseSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResumeSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResumeSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResetSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResetSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResizeSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResizeSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::LanguageChangedSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& LanguageChangedSignal();
+
+public:
+
+  /**
+   * Called when the framework is initialised.
+   *
+   * @param[in] app The application instance
+   */
+  void OnInit( Dali::Application& app );
+
+  /**
+   * Called when the framework is terminated.
+   *
+   * @param[in] app The application instance
+   */
+  void OnTerminate( Dali::Application& app );
+
+  /**
+   * Called when the framework is paused.
+   *
+   * @param[in] app The application instance
+   */
+  void OnPause( Dali::Application& app );
+
+  /**
+   * Called when the framework resumes from a paused state.
+   *
+   * @param[in] app The application instance
+   */
+  void OnResume( Dali::Application& app );
+
+  /**
+   * Called when the framework informs the application that it should reset itself.
+   *
+   * @param[in] app The application instance
+   */
+  void OnReset( Dali::Application& app );
+
+  /**
+   * Called when the framework informs the application that the language of the device has changed.
+   *
+   * @param[in] app The application instance
+   */
+  void OnLanguageChanged( Dali::Application& app );
+
+  /**
+   * Signal handler when the adaptor's window resizes itself.
+   *
+   * @param[in] app The application instance
+   */
+  void OnResize( Dali::Application& app );
+
+protected:
+
+  /**
+   * Virtual Destructor.
+   */
+  virtual ~LifecycleController();
+
+private:
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitInitSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitTerminateSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitPauseSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResumeSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResetSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResizeSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitLanguageChangedSignal();
+
+private:
+
+  // Signals
+  Dali::LifecycleController::LifecycleSignalType mInitSignal;
+  Dali::LifecycleController::LifecycleSignalType mTerminateSignal;
+  Dali::LifecycleController::LifecycleSignalType mPauseSignal;
+  Dali::LifecycleController::LifecycleSignalType mResumeSignal;
+  Dali::LifecycleController::LifecycleSignalType mResetSignal;
+  Dali::LifecycleController::LifecycleSignalType mResizeSignal;
+  Dali::LifecycleController::LifecycleSignalType mLanguageChangedSignal;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::LifecycleController& GetImplementation(Dali::LifecycleController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "Controller handle is empty");
+  BaseObject& handle = controller.GetBaseObject();
+  return static_cast<Internal::Adaptor::LifecycleController&>(handle);
+}
+
+inline const Internal::Adaptor::LifecycleController& GetImplementation(const Dali::LifecycleController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "Controller handle is empty");
+  const BaseObject& handle = controller.GetBaseObject();
+  return static_cast<const Internal::Adaptor::LifecycleController&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_LIFECYCLE_CONTROLLER_H__
diff --git a/adaptors/common/locale-utils.cpp b/adaptors/common/locale-utils.cpp
new file mode 100644 (file)
index 0000000..2389eeb
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "locale-utils.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Locale
+{
+
+using Dali::VirtualKeyboard::TextDirection;
+using Dali::VirtualKeyboard::LeftToRight;
+using Dali::VirtualKeyboard::RightToLeft;
+
+namespace
+{
+
+struct LocaleDirection
+{
+  const char * locale;
+  const char * name;
+  TextDirection direction;
+};
+
+const LocaleDirection LOCALE_DIRECTION_LOOKUP_TABLE[] =
+{
+  { "af", "Afrikaans",          LeftToRight },
+  { "am", "Amharic",            LeftToRight },
+  { "ar", "Arabic",             RightToLeft },
+  { "as", "Assamese",           LeftToRight },
+  { "az", "Azeri",              LeftToRight },
+  { "be", "Belarusian",         LeftToRight },
+  { "bg", "Bulgarian",          LeftToRight },
+  { "bn", "Bengali",            LeftToRight },
+  { "bo", "Tibetan",            LeftToRight },
+  { "bs", "Bosnian",            LeftToRight },
+  { "ca", "Catalan",            LeftToRight },
+  { "cs", "Czech",              LeftToRight },
+  { "cy", "Welsh",              LeftToRight },
+  { "da", "Danish",             LeftToRight },
+  { "de", "German",             LeftToRight },
+  { "dv", "Divehi",             RightToLeft },
+  { "el", "Greek",              LeftToRight },
+  { "en", "English",            LeftToRight },
+  { "es", "Spanish",            LeftToRight },
+  { "et", "Estonian",           LeftToRight },
+  { "eu", "Basque",             LeftToRight },
+  { "fa", "Farsi",              RightToLeft },
+  { "fi", "Finnish",            LeftToRight },
+  { "fo", "Faroese",            LeftToRight },
+  { "fr", "French",             LeftToRight },
+  { "gd", "Gaelic",             LeftToRight },
+  { "gl", "Galician",           LeftToRight },
+  { "gn", "Guarani",            LeftToRight },
+  { "gu", "Gujarati",           LeftToRight },
+  { "he", "Hebrew",             RightToLeft },
+  { "hi", "Hindi",              LeftToRight },
+  { "hr", "Croatian",           LeftToRight },
+  { "hu", "Hungarian",          LeftToRight },
+  { "hy", "Armenian",           LeftToRight },
+  { "id", "Indonesian",         LeftToRight },
+  { "is", "Icelandic",          LeftToRight },
+  { "it", "Italian",            LeftToRight },
+  { "ja", "Japanese",           LeftToRight },
+  { "ka", "Georgian",           LeftToRight },
+  { "kk", "Kazakh",             RightToLeft },
+  { "km", "Khmer",              LeftToRight },
+  { "kn", "Kannada",            LeftToRight },
+  { "ko", "Korean",             LeftToRight },
+  { "ks", "Kashmiri",           RightToLeft },
+  { "la", "Latin",              LeftToRight },
+  { "lo", "Lao",                LeftToRight },
+  { "lt", "Lithuanian",         LeftToRight },
+  { "lv", "Latvian",            LeftToRight },
+  { "mi", "Maori",              LeftToRight },
+  { "mk", "FYRO Macedonia",     LeftToRight },
+  { "ml", "Malayalam",          LeftToRight },
+  { "mn", "Mongolian",          LeftToRight },
+  { "mr", "Marathi",            LeftToRight },
+  { "ms", "Malay",              LeftToRight },
+  { "mt", "Maltese",            LeftToRight },
+  { "my", "Burmese",            LeftToRight },
+  { "nb", "Norwegian: Bokml",   LeftToRight },
+  { "ne", "Nepali",             LeftToRight },
+  { "nl", "Dutch",              LeftToRight },
+  { "nn", "Norwegian: Nynorsk", LeftToRight },
+  { "or", "Oriya",              LeftToRight },
+  { "pa", "Punjabi",            LeftToRight },
+  { "pl", "Polish",             LeftToRight },
+  { "pt", "Portuguese",         LeftToRight },
+  { "rm", "Raeto-Romance",      LeftToRight },
+  { "ro", "Romanian",           LeftToRight },
+  { "ru", "Russian",            LeftToRight },
+  { "sa", "Sanskrit",           LeftToRight },
+  { "sb", "Sorbian",            LeftToRight },
+  { "sd", "Sindhi",             LeftToRight },
+  { "si", "Sinhala",            LeftToRight },
+  { "sk", "Slovak",             LeftToRight },
+  { "sl", "Slovenian",          LeftToRight },
+  { "so", "Somali",             LeftToRight },
+  { "sq", "Albanian",           LeftToRight },
+  { "sr", "Serbian",            LeftToRight },
+  { "sv", "Swedish",            LeftToRight },
+  { "sw", "Swahili",            LeftToRight },
+  { "ta", "Tamil",              LeftToRight },
+  { "te", "Telugu",             LeftToRight },
+  { "tg", "Tajik",              RightToLeft },
+  { "th", "Thai",               LeftToRight },
+  { "tk", "Turkmen",            LeftToRight },
+  { "tn", "Setsuana",           LeftToRight },
+  { "tr", "Turkish",            LeftToRight },
+  { "ts", "Tsonga",             LeftToRight },
+  { "tt", "Tatar",              LeftToRight },
+  { "uk", "Ukrainian",          LeftToRight },
+  { "ur", "Urdu",               RightToLeft },
+  { "uz", "Uzbek",              LeftToRight },
+  { "vi", "Vietnamese",         LeftToRight },
+  { "xh", "Xhosa",              LeftToRight },
+  { "yi", "Yiddish",            RightToLeft },
+  { "zh", "Chinese",            LeftToRight },
+  { "zu", "Zulu",               LeftToRight },
+
+  { NULL, NULL, LeftToRight }
+};
+
+} // unnamed namespace
+
+TextDirection GetTextDirection( std::string locale )
+{
+  TextDirection direction( LeftToRight );
+
+  if ( !locale.empty() && locale.size() > 2 )
+  {
+    // We're only interested in the first two characters
+    locale.resize(2);
+
+    for ( const LocaleDirection* iter = &LOCALE_DIRECTION_LOOKUP_TABLE[0]; iter->locale; ++iter )
+    {
+      if ( !locale.compare( iter->locale ) )
+      {
+        direction = iter->direction;
+        break;
+      }
+    }
+  }
+
+  return direction;
+}
+
+} // namespace Locale
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/locale-utils.h b/adaptors/common/locale-utils.h
new file mode 100644 (file)
index 0000000..0db57a9
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __DALI_INTERNAL_LOCALE_UTILS_H__
+#define __DALI_INTERNAL_LOCALE_UTILS_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+// INTERNAL INCLUDES
+#include <virtual-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Locale
+{
+
+Dali::VirtualKeyboard::TextDirection GetTextDirection( std::string locale );
+
+} // namespace Locale
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_LOCALE_UTILS_H__
diff --git a/adaptors/common/native-bitmap-buffer-impl.cpp b/adaptors/common/native-bitmap-buffer-impl.cpp
new file mode 100644 (file)
index 0000000..7f5ae17
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "native-bitmap-buffer-impl.h"
+
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+
+// INTERNAL HEADERS
+#include <common/gl/gl-implementation.h>
+#include <common/gl/egl-factory.h>
+#include <common/gl/egl-implementation.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+NativeBitmapBuffer::NativeBitmapBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pFormat )
+: mWidth(width),
+  mHeight(height),
+  mPixelFormat(pFormat),
+  mLastReadBuffer(NULL),
+  mYInverted( true ),
+  mInitTexture( false )
+{
+  DALI_ASSERT_ALWAYS( adaptor );
+  mBuffer = new Integration::LocklessBuffer( width * height * Pixel::GetBytesPerPixel(pFormat) );
+  mGlAbstraction = &(adaptor->GetGlAbstraction());
+
+  mYInverted = adaptor->GetEGLFactory().GetImplementation()->IsPixmapYInverted();
+}
+
+NativeBitmapBuffer::~NativeBitmapBuffer()
+{
+  delete mBuffer;
+}
+
+void NativeBitmapBuffer::PrepareTexture()
+{
+  DALI_ASSERT_ALWAYS( mBuffer );
+  GLenum pixelFormat = GL_RGBA;
+  GLenum pixelDataType = GL_UNSIGNED_BYTE;
+
+  Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelFormat );
+
+  const unsigned char* buf = mBuffer->Read();
+
+  if( buf && buf != mLastReadBuffer ) // Prevent same buffer being uploaded multiple times
+  {
+    mLastReadBuffer = buf;
+
+    if( mYInverted )
+    {
+      // The active texture has already been set to a sampler and bound.
+      mGlAbstraction->TexImage2D( GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, buf );
+    }
+    else
+    {
+      if( !mInitTexture )
+      {
+        mGlAbstraction->TexImage2D( GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, NULL );
+        mInitTexture = true;
+      }
+
+      for( unsigned int i = 0; i < mHeight; i++ )
+      {
+        mGlAbstraction->TexSubImage2D( GL_TEXTURE_2D, 0, 0, mHeight - i - 1, mWidth, 1, pixelFormat, pixelDataType, buf + (i * mWidth * Pixel::GetBytesPerPixel( mPixelFormat ) ) );
+      }
+    }
+  }
+}
+
+void NativeBitmapBuffer::Write( const unsigned char *src, size_t size )
+{
+  mBuffer->Write( src, size ); // Write will cause LocklessBuffer to switch to the other buffer
+}
+
+bool NativeBitmapBuffer::GlExtensionCreate()
+{
+  return true;
+}
+
+void NativeBitmapBuffer::GlExtensionDestroy()
+{
+}
+
+unsigned int NativeBitmapBuffer::TargetTexture()
+{
+  return 0;
+}
+
+unsigned int NativeBitmapBuffer::GetWidth() const
+{
+  return mWidth;
+}
+
+unsigned int NativeBitmapBuffer::GetHeight() const
+{
+  return mHeight;
+}
+
+bool NativeBitmapBuffer::RequiresBlending() const
+{
+  return Pixel::HasAlpha( mPixelFormat );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/native-bitmap-buffer-impl.h b/adaptors/common/native-bitmap-buffer-impl.h
new file mode 100644 (file)
index 0000000..94891ed
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef __DALI_NATIVE_BITMAP_BUFFER_H__
+#define __DALI_NATIVE_BITMAP_BUFFER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL HEADERS
+#include <dali/public-api/images/native-image-interface.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/lockless-buffer.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL HEADERS
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class NativeBitmapBuffer;
+typedef IntrusivePtr<NativeBitmapBuffer> NativeBitmapBufferPtr;
+
+/**
+ * A Bitmap-based implementation of the NativeImage interface.
+ */
+class NativeBitmapBuffer : public NativeImageInterface
+{
+
+public:
+  /**
+   * Constructor.
+   * @param adaptor Adaptor used
+   * @param width width of image
+   * @param height height of image
+   * @param pixelFormat pixel format for image
+   */
+  NativeBitmapBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pixelFormat );
+
+  /**
+   * virtual destructor
+   */
+  virtual ~NativeBitmapBuffer();
+
+  /**
+   * Write to buffer. Does not block.
+   * @param[in] src  data source
+   * @param[in] size size of data in bytes
+   * @return true if successful, false if currently reading from buffer in render thread
+   */
+  void Write( const unsigned char* src, size_t size );
+
+public:
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual unsigned int GetWidth() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual unsigned int GetHeight() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const;
+
+private:
+  NativeBitmapBuffer( const NativeBitmapBuffer& );             ///< not defined
+  NativeBitmapBuffer& operator =( const NativeBitmapBuffer& ); ///< not defined
+  NativeBitmapBuffer(); ///< not defined
+
+private:
+  Integration::GlAbstraction*  mGlAbstraction; ///< GlAbstraction used
+
+  Integration::LocklessBuffer* mBuffer;        ///< bitmap data double buffered
+  unsigned int                 mWidth;         ///< Image width
+  unsigned int                 mHeight;        ///< Image height
+  Pixel::Format                mPixelFormat;   ///< Image pixelformat
+  const unsigned char*         mLastReadBuffer; ///< last buffer that was read
+  bool                         mYInverted;     ///< Whether image is y-inverted
+  bool                         mInitTexture;   ///< Init image
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_NATIVE_BITMAP_BUFFER_H__
diff --git a/adaptors/common/networking/socket-factory.cpp b/adaptors/common/networking/socket-factory.cpp
new file mode 100644 (file)
index 0000000..30a2615
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// CLASS HEADER
+#include "socket-factory.h"
+
+// INTERNAL INCLUDES
+#include <networking/socket-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+SocketInterface* SocketFactory::NewSocket( SocketInterface::Protocol protocol  )
+{
+  return new Socket( protocol );
+}
+
+void SocketFactory::DestroySocket( SocketInterface* socketInterface )
+{
+  Socket* socket( static_cast<Socket* >( socketInterface ));
+  delete socket;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/adaptors/common/networking/socket-factory.h b/adaptors/common/networking/socket-factory.h
new file mode 100644 (file)
index 0000000..735d724
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H__
+#define __DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H__
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <base/interfaces/socket-factory-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief concrete implementation of the socket factory interface
+ */
+class SocketFactory : public SocketFactoryInterface
+{
+public:
+
+
+  /**
+   * @brief Constructor
+   */
+  SocketFactory( )
+  {
+  }
+
+  /**
+   * @brief destructor
+   */
+  virtual ~SocketFactory()
+  {
+  }
+
+  /**
+   * @copydoc SocketFactoryInterface::NewSocket()
+   */
+  virtual SocketInterface* NewSocket( SocketInterface::Protocol protocol  );
+
+  /**
+   * @copydoc SocketFactoryInterface::DestroySocket()
+   */
+  virtual void DestroySocket( SocketInterface* socket  );
+
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H__
diff --git a/adaptors/common/networking/socket-impl.cpp b/adaptors/common/networking/socket-impl.cpp
new file mode 100644 (file)
index 0000000..edb823d
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "socket-impl.h"
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dali/integration-api/debug.h>
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10 ; // limit maximum size to write to 10 MB
+}
+
+Socket::Socket( Protocol protocol , int fileDescriptor )
+:mSocketFileDescriptor( fileDescriptor ),
+ mBound(false),
+ mListening(false),
+ mQuitPipeCreated(false),
+ mBlocked(false)
+{
+  int addressFamily( AF_INET );
+  int netProtocol( IPPROTO_TCP );
+  int type( SOCK_STREAM );    // for TCP
+
+  if( protocol == UDP )
+  {
+    type = SOCK_DGRAM;
+    netProtocol = IPPROTO_UDP;
+  }
+  if( mSocketFileDescriptor == -1)
+  {
+    mSocketFileDescriptor = socket( addressFamily,type, netProtocol);
+  }
+  else
+  {
+    // socket already open
+    mBound = true;
+  }
+}
+
+Socket::~Socket()
+{
+  if( SocketIsOpen() )
+  {
+    CloseSocket();
+  }
+}
+
+bool Socket::SocketIsOpen() const
+{
+  return (mSocketFileDescriptor != -1);
+}
+
+bool Socket::CloseSocket()
+{
+
+  if( ! SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket already closed or is invalid \n");
+    return false;
+  }
+
+  int ret = close( mSocketFileDescriptor );
+  mSocketFileDescriptor = -1;
+  mListening = false;
+  mBound = false;
+
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("Socket close failed");
+    return false;
+  }
+  return true;
+}
+
+bool Socket::Bind( uint16_t port )
+{
+  if( ! SocketIsOpen() || mBound )
+  {
+     DALI_LOG_ERROR("Socket is invalid, or already bound");
+     return false;
+  }
+  struct sockaddr_in serverAddress;
+
+  memset( &serverAddress, 0, sizeof(serverAddress) );
+  serverAddress.sin_family = AF_INET;                             // internet
+  serverAddress.sin_port = htons( port );  //  host-to-net short (16-bit) translation
+  serverAddress.sin_addr.s_addr = htonl( INADDR_ANY ); //  binds the socket to all available interfaces
+
+  int ret = bind( mSocketFileDescriptor,
+                  (struct sockaddr* ) &serverAddress,
+                  sizeof(serverAddress));
+
+  if( ret == -1 )
+  {
+    char buf[512];
+    DALI_LOG_ERROR( "bind failed for port %d %s \n", port, strerror_r( errno, buf, 512 ) );
+    return false;
+  }
+
+  mBound = true;
+
+  return true;
+}
+
+bool Socket::Listen( int blacklog)
+{
+  if( ! mBound || mListening )
+  {
+    DALI_LOG_ERROR("socket is not bound, or already opened for listening");
+    return false;
+  }
+  int ret =  listen( mSocketFileDescriptor, blacklog);
+
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("Listen failed");
+    return false;
+  }
+
+  mListening = true;
+
+  return true;
+}
+
+SocketInterface* Socket::Accept() const
+{
+  if( !mListening )
+  {
+    DALI_LOG_ERROR("socket is not being listened to");
+    return NULL;
+  }
+
+  struct sockaddr clientAddress;
+
+  socklen_t addressLength(sizeof(sockaddr_in));
+
+  int clientFileDescriptor = accept( mSocketFileDescriptor, &clientAddress, &addressLength);
+  if( clientFileDescriptor == -1 )
+  {
+     DALI_LOG_ERROR("Accept failed");
+     return NULL;
+  }
+
+  // create a new socket, only TCP supports connections
+  Socket* client = new Socket( TCP, clientFileDescriptor );
+
+  return client;
+}
+
+bool Socket::CreateQuitPipe()
+{
+  if( !mQuitPipeCreated )
+  {
+    // create a pipe file descriptor to be able to break from the Select statement
+    //
+    int ret = pipe( mQuitPipe );
+    if( ret != 0)
+    {
+      DALI_LOG_ERROR("Pipe creation failed");
+      return false;
+    }
+    mQuitPipeCreated = true;
+  }
+  return true;
+}
+void Socket::DeleteQuitPipe()
+{
+  if( mQuitPipeCreated )
+  {
+    close( mQuitPipe[0] );
+    close( mQuitPipe[1] );
+  }
+}
+
+SocketInterface::SelectReturn Socket::Select()
+{
+  bool ok = CreateQuitPipe();
+  if( !ok )
+  {
+    return ERROR;
+  }
+
+  fd_set  readFileDescriptors, exceptFileDescriptors;
+  FD_ZERO(&readFileDescriptors);
+  FD_ZERO(&exceptFileDescriptors);
+
+  FD_SET(mSocketFileDescriptor,&readFileDescriptors );
+  FD_SET(mQuitPipe[0],&readFileDescriptors );
+
+  FD_SET(mSocketFileDescriptor,&exceptFileDescriptors);
+
+  unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0]: mSocketFileDescriptor;
+
+  for( ;; )
+  {
+    // this will block waiting for file descriptors
+    int ret = select( maxFd+1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL );
+    if( ret == -1 )
+    {
+      DALI_LOG_ERROR("select failed");
+      return ERROR;
+    }
+    else if ( FD_ISSET( mQuitPipe[0] , &readFileDescriptors ))
+    {
+      // ExitSelect() called
+      return QUIT;
+    }
+    else if ( FD_ISSET( mSocketFileDescriptor, &readFileDescriptors ))
+    {
+      // socket data received
+      return DATA_AVAILABLE;
+    }
+  }
+  return QUIT;
+}
+
+void Socket::ExitSelect()
+{
+  if( mQuitPipeCreated )
+  {
+    // write a single character to the pipe (can be anything)
+    char c = ' ';
+    int ret = write( mQuitPipe[1], &c, 1);
+    if( ret < 1 )
+    {
+      DALI_LOG_ERROR("ExitSelect failed!\n");
+    }
+    return;
+  }
+}
+
+bool Socket::ReuseAddress( bool reUse  )
+{
+  if( ! SocketIsOpen() | mBound )
+  {
+    DALI_LOG_ERROR("Socket is invalid or already bound \n");
+    return false;
+  }
+
+  int reUseInteger = reUse; // convert it to an int
+
+  int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
+  if( ret == -1 )
+  {
+    char buf[512];
+    DALI_LOG_ERROR( "SO_REUSEADDR option failed %s \n", strerror_r( errno, buf, 512 ) );
+    return false;
+  }
+  return true;
+}
+
+bool Socket::SetBufferSize( SocketInterface::BufferType type, unsigned int size )
+{
+  if( ! SocketIsOpen() || mBound )
+  {
+    DALI_LOG_ERROR("Socket is invalid or already bound \n");
+    return false;
+  }
+  int option = SO_RCVBUF;
+  if( type == SocketInterface::SEND_BUFFER )
+  {
+    option = SO_SNDBUF;
+  }
+
+  int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET,option,&size,sizeof(size));
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF  option failed \n");
+    return false;
+  }
+  return true;
+}
+
+bool Socket::Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead )
+{
+  bytesRead = 0;
+
+  if( !SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket is invalid \n");
+    return false;
+  }
+
+  bytesRead = read( mSocketFileDescriptor, buffer, bufferSizeInBytes );
+
+  return true;
+}
+
+bool Socket::Write( const void* buffer, unsigned int bufferSizeInBytes )
+{
+  if( !SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket is invalid \n");
+    return false;
+  }
+
+  // check we don't try to write more than 10MB ( this can be increased if required)
+  if( bufferSizeInBytes > MAX_SOCKET_DATA_WRITE_SIZE )
+  {
+    DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
+    return false;
+  }
+
+  int bytesWritten = 0;
+
+  // write isn't guaranteed to write the entire buffer in one go
+
+  while(  bytesWritten != static_cast< int>(bufferSizeInBytes))
+  {
+    const char* byteBuffer = static_cast<const char *>( buffer );
+    byteBuffer+=bytesWritten;
+
+    int ret = write( mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten );
+    if( ret < 1)
+    {
+      DALI_LOG_ERROR("Socket writer error \n");
+      return false;
+    }
+    else
+    {
+      bytesWritten += ret;
+    }
+  }
+  return true;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
+
diff --git a/adaptors/common/networking/socket-impl.h b/adaptors/common/networking/socket-impl.h
new file mode 100644 (file)
index 0000000..016127a
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H__
+#define __DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <base/interfaces/socket-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Concrete implementation of a socket under Linux.
+ *
+ * Provides automatic closing of socket on destruction.
+ */
+class Socket : public SocketInterface
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param protocol network protocol
+   * @param fileDescriptor option file descriptor if the socket is already open
+   */
+  Socket( Protocol protocol , int fileDescriptor = -1 );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketIsOpen()
+   */
+  virtual bool SocketIsOpen() const;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::CloseSocket
+   */
+  virtual bool CloseSocket();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Bind
+   */
+  virtual bool Bind( uint16_t port ) ;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Listen
+   */
+  virtual bool Listen( int blacklog);
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Accept
+   */
+  virtual SocketInterface* Accept() const ;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Select
+   */
+  virtual SelectReturn Select( );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::ExitSelect
+   */
+  virtual void ExitSelect();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Recieve
+   */
+  virtual bool Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Send
+   */
+  virtual bool Write( const void* buffer, unsigned int bufferLength );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::ReuseAddress
+   */
+  virtual bool ReuseAddress( bool reUse );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::SetBufferSize
+   *
+   */
+  virtual bool SetBufferSize( SocketInterface::BufferType type, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~Socket();
+
+private:
+
+
+  /**
+   * @brief Helper to create the quit pipe
+   */
+  bool CreateQuitPipe();
+
+  /**
+   * @brief  Helper to delete the quit pipe
+   */
+  void DeleteQuitPipe();
+
+  int mSocketFileDescriptor; ///< file descriptor
+  int mQuitPipe[2];          ///< Pipe to inform Select to quit.
+  bool mBound:1;             ///< whether the socket is bound
+  bool mListening:1;         ///< whether the socket is being listen to
+  bool mQuitPipeCreated:1;   ///< whether the quit pipe has been created
+  bool mBlocked:1;           ///< whether the socket is blocked waiting for a connection
+};
+
+
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H__
diff --git a/adaptors/common/object-profiler.cpp b/adaptors/common/object-profiler.cpp
new file mode 100644 (file)
index 0000000..9903b79
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "object-profiler.h"
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/profiling.h>
+#include <dali/public-api/actors/image-actor.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/type-registry.h>
+
+using std::string;
+using namespace Dali::Integration::Profiling;
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+ObjectProfiler::ObjectProfiler( unsigned int timeInterval )
+{
+  // This class must be created after the Stage; this means it doesn't count the initial objects
+  // that are created by the stage (base layer, default camera actor)
+  mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
+
+  mTimer = Dali::Timer::New( timeInterval * 1000 );
+  mTimer.TickSignal().Connect( this, &ObjectProfiler::OnTimeout );
+  mTimer.Start();
+
+  mObjectRegistry.ObjectCreatedSignal().Connect( this, &ObjectProfiler::OnObjectCreated );
+  mObjectRegistry.ObjectDestroyedSignal().Connect( this, &ObjectProfiler::OnObjectDestroyed );
+}
+
+ObjectProfiler::~ObjectProfiler()
+{
+}
+
+void ObjectProfiler::DisplayInstanceCounts()
+{
+  InstanceCountMapIterator iter = mInstanceCountMap.begin();
+  InstanceCountMapIterator end = mInstanceCountMap.end();
+
+  for( ; iter != end; iter++ )
+  {
+    int memorySize = GetMemorySize(iter->first, iter->second);
+    if( memorySize > 0 )
+    {
+      LogMessage( Debug::DebugInfo, "%-30s: % 4d  Memory MemorySize: ~% 6.1f kB\n",
+                  iter->first.c_str(), iter->second, memorySize / 1024.0f );
+    }
+    else
+    {
+      LogMessage( Debug::DebugInfo, "%-30s: % 4d\n",
+                  iter->first.c_str(), iter->second );
+    }
+  }
+  LogMessage(Debug::DebugInfo, "\n");
+
+  int quadCount = 0;
+
+  // Count number of quads:
+
+  for( InstanceTypes::iterator iter = mInstanceTypes.begin(), end = mInstanceTypes.end(); iter != end; ++iter )
+  {
+    if( iter->second.compare("ImageActor") == 0 )
+    {
+      BaseHandle handle(iter->first);
+      Dali::ImageActor imageActor = Dali::ImageActor::DownCast(handle);
+      if( imageActor )
+      {
+        if( imageActor.GetStyle() == Dali::ImageActor::STYLE_QUAD )
+        {
+          quadCount++;
+        }
+      }
+    }
+  }
+
+  LogMessage(Debug::DebugInfo, "Number of image actors using Quad style: %d\n", quadCount);
+}
+
+bool ObjectProfiler::OnTimeout()
+{
+  DisplayInstanceCounts();
+  return true;
+}
+
+void ObjectProfiler::OnObjectCreated(BaseHandle handle)
+{
+  string theType = handle.GetTypeName();
+  if( theType.empty() )
+  {
+    DALI_LOG_ERROR("Object created from an unregistered type\n");
+    theType = "<Unregistered>";
+  }
+
+  mInstanceTypes.push_back(InstanceTypePair(&handle.GetBaseObject(), theType));
+
+  InstanceCountMapIterator iter = mInstanceCountMap.find(theType);
+  if( iter == mInstanceCountMap.end() )
+  {
+    InstanceCountPair instanceCount(theType, 1);
+    mInstanceCountMap.insert(instanceCount);
+  }
+  else
+  {
+    iter->second++;
+  }
+}
+
+void ObjectProfiler::OnObjectDestroyed(const Dali::RefObject* object)
+{
+  const BaseObject* baseObject = static_cast<const BaseObject*>(object);
+
+  InstanceTypes::iterator end = mInstanceTypes.end();
+  for( InstanceTypes::iterator iter = mInstanceTypes.begin(); iter != end; iter++)
+  {
+    if( iter->first == baseObject )
+    {
+      const std::string& theType = iter->second;
+      if( !theType.empty() )
+      {
+        InstanceCountMapIterator countIter = mInstanceCountMap.find(theType);
+        if( countIter != mInstanceCountMap.end() )
+        {
+          countIter->second--;
+        }
+      }
+      mInstanceTypes.erase( iter );
+      break;
+    }
+  }
+}
+
+int ObjectProfiler::GetMemorySize(const std::string& name, int count)
+{
+  struct MemoryMemorySize
+  {
+    std::string name;
+    int memorySize;
+  };
+  MemoryMemorySize memoryMemorySizes[] =
+    {
+      { "Animation", ANIMATION_MEMORY_SIZE },
+      { "Constraint", CONSTRAINT_MEMORY_SIZE },
+      { "Actor", ACTOR_MEMORY_SIZE },
+      { "Layer", LAYER_MEMORY_SIZE },
+      { "CameraActor", CAMERA_ACTOR_MEMORY_SIZE },
+      { "ImageActor", IMAGE_ACTOR_MEMORY_SIZE },
+      { "Image", IMAGE_MEMORY_SIZE },
+      { "Renderer", RENDERER_MEMORY_SIZE },
+      { "Geometry", GEOMETRY_MEMORY_SIZE },
+      { "PropertyBuffer", PROPERTY_BUFFER_MEMORY_SIZE },
+      { "Material", MATERIAL_MEMORY_SIZE },
+      { "Sampler", SAMPLER_MEMORY_SIZE },
+      { "Shader", SHADER_MEMORY_SIZE },
+    };
+
+  for( size_t i=0; i<sizeof(memoryMemorySizes)/sizeof(MemoryMemorySize); i++ )
+  {
+    if( memoryMemorySizes[i].name.compare(name) == 0 )
+    {
+      return count * memoryMemorySizes[i].memorySize;
+    }
+  }
+  return 0;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/object-profiler.h b/adaptors/common/object-profiler.h
new file mode 100644 (file)
index 0000000..eca7972
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef __DALI_ADAPTOR_OBJECT_PROFILER_H__
+#define __DALI_ADAPTOR_OBJECT_PROFILER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/object-registry.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/map-wrapper.h>
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <timer.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Class to profile the number of instances of Objects in the system
+ */
+class ObjectProfiler : public ConnectionTracker
+{
+public:
+
+  /**
+   * Constructor
+   * @param timeInterval to specify the frequency of reporting
+   */
+  ObjectProfiler( unsigned int timeInterval );
+
+  /**
+   * Destructor
+   */
+  ~ObjectProfiler();
+
+  /**
+   * Display a list of types with the current number of instances in the system
+   */
+  void DisplayInstanceCounts();
+
+private:
+  /**
+   * If timer is running, display the instance counts
+   */
+  bool OnTimeout();
+
+  /**
+   * Callback used when objects are created. Increases instance count for that object type
+   * @param[in] handle of the created object
+   */
+  void OnObjectCreated(BaseHandle handle);
+
+  /**
+   * Callback used when objects are created. Decreases instance count for that object type
+   * @param[in] object The object being destroyed
+   */
+  void OnObjectDestroyed(const Dali::RefObject* object);
+
+  /**
+   * Get the memory size of the given object
+   */
+  int GetMemorySize(const std::string& name, int count);
+
+private:
+  typedef std::map<std::string, int> InstanceCountMap;
+  typedef std::pair<const std::string, int> InstanceCountPair;
+  typedef InstanceCountMap::iterator InstanceCountMapIterator;
+  typedef std::pair<BaseObject*, std::string> InstanceTypePair;
+  typedef std::vector<InstanceTypePair> InstanceTypes;
+
+  Dali::ObjectRegistry    mObjectRegistry;
+  Dali::Timer             mTimer;
+  InstanceCountMap        mInstanceCountMap;
+  InstanceTypes           mInstanceTypes;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_ADAPTOR_OBJECT_PROFILER_H__
diff --git a/adaptors/common/orientation-impl.cpp b/adaptors/common/orientation-impl.cpp
new file mode 100644 (file)
index 0000000..cbd705e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "orientation-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <window-impl.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+Orientation* Orientation::New(Window* window)
+{
+  Orientation* orientation = new Orientation(window);
+
+  return orientation;
+}
+
+Orientation::Orientation(Window* window)
+: mWindow(window),
+  mOrientation(0),
+  mWindowWidth(0),
+  mWindowHeight(0)
+{
+}
+
+Orientation::~Orientation()
+{
+  // Note, there is only one orientation object that's owned by window,
+  // so it will live longer than adaptor. (hence, no need to remove rotation observer)
+}
+
+void Orientation::SetAdaptor(Dali::Adaptor& adaptor)
+{
+  Adaptor& adaptorImpl = Adaptor::GetImplementation(adaptor);
+  adaptorImpl.SetRotationObserver(this);
+}
+
+int Orientation::GetDegrees() const
+{
+  return mOrientation;
+}
+
+float Orientation::GetRadians() const
+{
+  return Math::PI * (float)mOrientation / 180.0f;
+}
+
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
+{
+  return mChangedSignal;
+}
+
+void Orientation::OnRotationPrepare( const RotationEvent& rotation )
+{
+  mOrientation  = rotation.angle;
+  mWindowWidth  = rotation.width;
+  mWindowHeight = rotation.height;
+}
+
+void Orientation::OnRotationRequest()
+{
+  // Emit signal
+  if( !mChangedSignal.Empty() )
+  {
+    Dali::Orientation handle( this );
+    mChangedSignal.Emit( handle );
+  }
+
+  if( mWindow != NULL )
+  {
+    mWindow->RotationDone( mOrientation, mWindowWidth, mWindowHeight );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/orientation-impl.h b/adaptors/common/orientation-impl.h
new file mode 100644 (file)
index 0000000..e49f133
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef __DALI_INTERNAL_ORIENTATION_H__
+#define __DALI_INTERNAL_ORIENTATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cmath>
+#include <dali/public-api/common/constants.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <orientation.h>
+#include <rotation-observer.h>
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Window;
+class Orientation;
+
+typedef IntrusivePtr<Orientation> OrientationPtr;
+
+class Orientation : public BaseObject, public RotationObserver
+{
+public:
+
+  typedef Dali::Orientation::OrientationSignalType OrientationSignalType;
+
+  static Orientation* New(Window* window);
+
+  /**
+   * Constructor
+   */
+  Orientation(Window* window);
+
+protected:
+  /**
+   * Destructor
+   */
+  virtual ~Orientation();
+
+public:
+  /**
+   * Set the adaptor for basic setup
+   * @param[in] adaptor The adaptor
+   */
+  void SetAdaptor(Dali::Adaptor& adaptor);
+
+  /**
+   * Returns the actual orientation in degrees
+   * @return The device's orientation
+   */
+  int GetDegrees() const;
+
+  /**
+   * Returns the actual orientation in radians
+   * @return The device's orientation
+   */
+  float GetRadians() const;
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Orientation::ChangedSignal()
+   */
+  OrientationSignalType& ChangedSignal();
+
+private:
+  /**
+   * @copydoc Dali::Internal::Adaptor::RotationObserver::OnRotationPrepare()
+   */
+  virtual void OnRotationPrepare( const RotationEvent& rotation );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::RotationObserver::OnRotationRequest()
+   */
+  virtual void OnRotationRequest( );
+
+  // Undefined
+  Orientation(const Orientation&);
+  Orientation& operator=(Orientation&);
+
+private:
+  /**
+   * Signals and sends event of orientation change.
+   */
+  void EmitOrientationChange();
+
+private:
+
+  Window*                                  mWindow;
+
+  OrientationSignalType mChangedSignal;
+
+  int                                      mOrientation;
+  int                                      mWindowWidth;
+  int                                      mWindowHeight;
+};
+
+inline Orientation& GetImplementation (Dali::Orientation& orientation)
+{
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+
+  BaseObject& handle = orientation.GetBaseObject();
+
+  return static_cast<Orientation&>(handle);
+}
+
+inline const Orientation& GetImplementation(const Dali::Orientation& orientation)
+{
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+
+  const BaseObject& handle = orientation.GetBaseObject();
+
+  return static_cast<const Orientation&>(handle);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ORIENTATION_H__
diff --git a/adaptors/common/performance-logger-impl.cpp b/adaptors/common/performance-logger-impl.cpp
new file mode 100644 (file)
index 0000000..8b36320
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <performance-logger-impl.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+PerformanceInterface* GetPerformanceInterface()
+{
+  if( Adaptor::IsAvailable() )
+  {
+    return Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetPerformanceInterface();
+  }
+
+  return NULL;
+}
+
+} // Anonymous namespace
+
+PerformanceLoggerPtr PerformanceLogger::New( const char* name )
+{
+  PerformanceLoggerPtr logger = new PerformanceLogger( name );
+  return logger;
+}
+
+PerformanceLogger::PerformanceLogger( const char* name )
+: mContext( 0 )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    mContext = performance->AddContext( name );
+  }
+}
+
+PerformanceLogger::~PerformanceLogger()
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->RemoveContext( mContext );
+  }
+}
+
+void PerformanceLogger::AddMarker( Dali::PerformanceLogger::Marker markerType )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    PerformanceInterface::MarkerType newMarkerType = PerformanceInterface::START;
+    switch( markerType )
+    {
+      case Dali::PerformanceLogger::START_EVENT:
+      {
+        newMarkerType = PerformanceInterface::START;
+        break;
+      }
+      case Dali::PerformanceLogger::END_EVENT:
+      {
+        newMarkerType = PerformanceInterface::END;
+        break;
+      }
+    }
+
+    performance->AddMarker( newMarkerType, mContext );
+  }
+}
+
+void PerformanceLogger::SetLoggingFrequency( unsigned int logFrequency)
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->SetLoggingFrequency( logFrequency, mContext );
+  }
+}
+
+void PerformanceLogger::EnableLogging( bool enable )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->EnableLogging( enable, mContext );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/performance-logger-impl.h b/adaptors/common/performance-logger-impl.h
new file mode 100644 (file)
index 0000000..f5d1c64
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef __DALI_INTERNAL_PERFORMANCE_LOGGER_H__
+#define __DALI_INTERNAL_PERFORMANCE_LOGGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/performance-interface.h>
+#include <performance-logger.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class PerformanceLogger;
+
+typedef IntrusivePtr<PerformanceLogger> PerformanceLoggerPtr;
+
+/**
+ * @brief Interface for the performance logger
+ */
+class PerformanceLogger : public BaseObject
+{
+public:
+
+  /**
+   * @brief Create a new logger
+   *
+   * @param[in] name The name of the logger. This needs to be a compile-time literal and alive for the whole lifetime of the performance logger.
+   * @return a new logger
+   */
+  static PerformanceLoggerPtr New( const char* name );
+
+  /**
+   * Constructor
+   * @param[in] name The name to assing to the logger
+   */
+  PerformanceLogger( const char* name );
+
+  /**
+   * Destructor.
+   */
+  virtual ~PerformanceLogger();
+
+  /**
+   * Add a performance marker
+   *
+   * @param markerType Performance marker type
+   */
+  void AddMarker( Dali::PerformanceLogger::Marker markerType );
+
+  /**
+   * Set the logging frequency
+   *
+   * @param logFrequency how often to log out in seconds
+   */
+  void SetLoggingFrequency( unsigned int logFrequency);
+
+  /**
+   * Set logging on or off for this logger
+   *
+   * @param[in] enable Enable logging or not
+   */
+  void EnableLogging( bool enable );
+
+private: // Implementation
+
+  // not implemented
+  PerformanceLogger( const PerformanceLogger& );
+  PerformanceLogger& operator=( const PerformanceLogger& );
+
+private:
+
+  PerformanceInterface::ContextId mContext;   ///< Context of this logger
+
+};
+
+// Helpers for public-api forwarding methods
+
+inline static Internal::Adaptor::PerformanceLogger& GetImplementation( Dali::PerformanceLogger& logger )
+{
+  DALI_ASSERT_ALWAYS( logger && "PerformanceLogger handle is empty" );
+
+  BaseObject& handle = logger.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::PerformanceLogger& >( handle );
+}
+
+inline static const  Internal::Adaptor::PerformanceLogger& GetImplementation( const Dali::PerformanceLogger& logger )
+{
+  DALI_ASSERT_ALWAYS( logger && "PerformanceLogger handle is empty" );
+
+  const BaseObject& handle = logger.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::PerformanceLogger& >( handle );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_PERFORMANCE_LOGGER_H__
diff --git a/adaptors/common/physical-keyboard-impl.cpp b/adaptors/common/physical-keyboard-impl.cpp
new file mode 100644 (file)
index 0000000..8cb8a66
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// CLASS HEADER
+#include <physical-keyboard-impl.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::PhysicalKeyboard PhysicalKeyboard::New()
+{
+  Dali::PhysicalKeyboard keyboardHandle;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    keyboardHandle = Dali::PhysicalKeyboard( new PhysicalKeyboard() );
+    service.Register( typeid( keyboardHandle ), keyboardHandle );
+  }
+
+  return keyboardHandle;
+}
+
+Dali::PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  Dali::PhysicalKeyboard keyboardHandle;
+
+  Dali::SingletonService service = SingletonService::Get();
+  if ( service )
+  {
+    BaseHandle handle = service.GetSingleton( typeid( Dali::PhysicalKeyboard ) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton to focus manager
+      keyboardHandle = Dali::PhysicalKeyboard( dynamic_cast< PhysicalKeyboard* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return keyboardHandle;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  return mAttached;
+}
+
+void PhysicalKeyboard::KeyReceived( bool fromPhysicalKeyboard )
+{
+  if ( mAttached != fromPhysicalKeyboard )
+  {
+    mAttached = fromPhysicalKeyboard;
+
+    Dali::PhysicalKeyboard handle( this );
+    mStatusChangedSignal.Emit( handle );
+  }
+}
+
+PhysicalKeyboard::~PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard::PhysicalKeyboard()
+: mAttached( false )
+{
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/adaptors/common/physical-keyboard-impl.h b/adaptors/common/physical-keyboard-impl.h
new file mode 100644 (file)
index 0000000..03aef0f
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef __DALI_INTERNAL_PHYSICAL_KEYBOARD_H__
+#define __DALI_INTERNAL_PHYSICAL_KEYBOARD_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <physical-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class PhysicalKeyboard : public BaseObject
+{
+public:
+
+  /**
+   * Creates a new instance of the PhysicalKeyboard.
+   */
+  static Dali::PhysicalKeyboard New();
+
+  /**
+   * Gets the singleton instance of the Physical Keyboard.
+   */
+  static Dali::PhysicalKeyboard Get();
+
+  /**
+   * @copydoc Dali::PhysicalKeyboard::IsAttached()
+   */
+  bool IsAttached() const;
+
+  /**
+   * Should be called by the EventHandler when a key is received. If it's received from a physical
+   * keyboard then the parameter should be true.
+   * @param[in]  fromPhysicalKeyboard  true if received from a physical keyboard, false otherwise.
+   */
+  void KeyReceived( bool fromPhysicalKeyboard );
+
+  // Signals
+
+  /**
+   * @copydoc Dali::PhysicalKeyboard::StatusChangedSignal()
+   */
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType& StatusChangedSignal() { return mStatusChangedSignal; }
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PhysicalKeyboard();
+
+private:
+
+  // Undefined
+  PhysicalKeyboard( const PhysicalKeyboard& );
+  PhysicalKeyboard& operator=( PhysicalKeyboard& );
+
+  /**
+   * Constructor
+   */
+  PhysicalKeyboard();
+
+private:
+
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType mStatusChangedSignal; ///< Status changed signal
+  bool mAttached; ///< true if the physical keyboard is attached, false otherwise
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline static Internal::Adaptor::PhysicalKeyboard& GetImplementation( PhysicalKeyboard& keyboard )
+{
+  DALI_ASSERT_ALWAYS( keyboard && "PhysicalKeyboard handle is empty" );
+
+  BaseObject& handle = keyboard.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::PhysicalKeyboard& >( handle );
+}
+
+inline static const  Internal::Adaptor::PhysicalKeyboard& GetImplementation( const PhysicalKeyboard& keyboard )
+{
+  DALI_ASSERT_ALWAYS( keyboard && "PhysicalKeyboard handle is empty" );
+
+  const BaseObject& handle = keyboard.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::PhysicalKeyboard& >( handle );
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_PHYSICAL_KEYBOARD_H__
diff --git a/adaptors/common/rotation-observer.h b/adaptors/common/rotation-observer.h
new file mode 100644 (file)
index 0000000..034b082
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __DALI_INTERNAL_ROTATION_OBSERVER_H__
+#define __DALI_INTERNAL_ROTATION_OBSERVER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct RotationEvent
+{
+  int angle;     ///< one of 0, 90, 180, 270
+  int winResize; ///< true if the window should be resized
+  int width;     ///< new window width
+  int height;    ///< new window height
+};
+
+
+/**
+ * The RotationObserver can be overridden in order to listen to rotation events.
+ */
+class RotationObserver
+{
+public:
+
+  /**
+   * Deriving classes should override this to be notified when we receive a RotationPrepare event.
+   * @param[in]  area  The area that has been rotationd.
+   */
+  virtual void OnRotationPrepare( const RotationEvent& rotation ) = 0;
+
+  /**
+   * Deriving classes should override this to be notifed when a RotationRequest event is received
+   */
+  virtual void OnRotationRequest( ) = 0;
+
+protected:
+
+  /**
+   * Protected Constructor.
+   */
+  RotationObserver()
+  {
+  }
+
+  /**
+   * Protected virtual destructor.
+   */
+  virtual ~RotationObserver()
+  {
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ROTATION_OBSERVER_H__
diff --git a/adaptors/common/server-connection.cpp b/adaptors/common/server-connection.cpp
new file mode 100644 (file)
index 0000000..8246cd5
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "server-connection.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+namespace
+{
+// Copied from ecore_evas_extn_engine.h
+// procotol version - change this as needed
+const int MAJOR( 0x2011 );
+}
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gIndicatorLogFilter;
+#endif
+
+ServerConnection::~ServerConnection()
+{
+  CloseConnection();
+
+  if( mService.name != NULL )
+  {
+    eina_stringshare_del(mService.name);
+  }
+
+  for( Handlers::iterator iter = mIpcHandlers.begin(); iter != mIpcHandlers.end(); ++iter )
+  {
+    ecore_event_handler_del(*iter);
+  }
+  mIpcHandlers.clear();
+}
+
+bool ServerConnection::IsConnected()
+{
+  return mConnected;
+}
+
+void ServerConnection::OnDisconnect()
+{
+  mConnected = false;
+  mIpcServer = NULL;
+  ecore_ipc_shutdown();
+  if( mObserver )
+  {
+    mObserver->ConnectionClosed();
+  }
+}
+
+bool ServerConnection::SendEvent( int event, const void *data, int size )
+{
+  return SendEvent(event, 0, 0, data, size);
+}
+
+bool ServerConnection::SendEvent( int event, int ref, int ref_to, const void *data, int size )
+{
+  if( mIpcServer != NULL  && ecore_ipc_server_send(mIpcServer, MAJOR, event, ref, ref_to, 0, data, size) )
+  {
+    return true;
+  }
+  else
+  {
+    return false;
+  }
+}
+
+Eina_Bool ServerConnection::IpcServerAdd( void *data, int /*type*/, void *event )
+{
+  DALI_LOG_INFO(gIndicatorLogFilter, Debug::General, "ServerConnection: IpcServerAdd\n" );
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool ServerConnection::IpcServerDel( void *data, int /*type*/, void *event )
+{
+  DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "ServerConnection: IpcServerDel\n" );
+
+  Ecore_Ipc_Event_Server_Del *e = static_cast<Ecore_Ipc_Event_Server_Del *>( event );
+  ServerConnection* connection = static_cast<ServerConnection*>( data );
+
+  if( connection != NULL )
+  {
+    if( connection->mIpcServer == e->server)
+    {
+      // No longer have a server connection
+      connection->OnDisconnect();
+    }
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool ServerConnection::IpcServerData( void *data, int /*type*/, void *event )
+{
+  DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "ServerConnection: IpcServerData\n" );
+
+  Ecore_Ipc_Event_Server_Data *e = static_cast<Ecore_Ipc_Event_Server_Data *>( event );
+  ServerConnection* connection = static_cast<ServerConnection*>( data );
+
+  if( connection != NULL )
+  {
+    if( connection != ecore_ipc_server_data_get( e->server ) )
+    {
+      return ECORE_CALLBACK_PASS_ON;
+    }
+
+    if( e->major != MAJOR )
+    {
+      return ECORE_CALLBACK_PASS_ON;
+    }
+
+    if( connection->mObserver )
+    {
+      connection->mObserver->DataReceived( event );
+    }
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+void ServerConnection::CloseConnection()
+{
+  if( mConnected )
+  {
+    DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "ServerConnection: CloseConnection\n" );
+
+    if( mIpcServer )
+    {
+      ecore_ipc_server_del( mIpcServer );
+      mIpcServer = NULL;
+    }
+
+    ecore_ipc_shutdown();
+    mConnected = false;
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/server-connection.h b/adaptors/common/server-connection.h
new file mode 100644 (file)
index 0000000..3838570
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_CONNECTION_H_
+#define __DALI_INTERNAL_ADAPTOR_CONNECTION_H_
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_Ipc.h>
+
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Makes a connection to a given service as a client
+ */
+class ServerConnection
+{
+public:
+  /**
+   * Observes the connection for data and connection closure
+   */
+  class Observer
+  {
+  public:
+    /**
+     * Inform that data has been received on the connection
+     * @param[in] event The event that has been received
+     */
+    virtual void DataReceived(void* event) = 0;
+
+    /**
+     * Inform the observer that the connection has closed
+     */
+    virtual void ConnectionClosed() = 0;
+  };
+
+public:
+  /**
+   * Constructor
+   * @param[in] serviceName The name of the service
+   * @param[in] serviceNumber The number of the service
+   * @param[in] isSystem Whether to connect as local user or system user
+   * @param[in] observer The connection observer
+   */
+  ServerConnection(const char *serviceName, int serviceNumber, bool isSystem, Observer* observer);
+
+  /**
+   * Destructor
+   */
+  ~ServerConnection();
+
+  /**
+   * Test if the connection is still alive
+   * @return True if the connection is still alive
+   */
+  bool IsConnected();
+
+  /**
+   * Disconnect from the server. Will trigger ConnectionClosed() observer callback
+   */
+  void OnDisconnect();
+
+  /**
+   * Send an event to the server.
+   * @param[in] event Event id
+   * @param[in] data  Pointer to the event data
+   * @param[in] size  Size of the event data
+   * @return whether the event is sent successfully or not
+   */
+  bool SendEvent( int event, const void *data, int size );
+
+  /**
+   * Send an event to the server.
+   * @param[in] event Event id
+   * @param[in] ref   Message Reference number
+   * @param[in] refTo Reference number of the message this refers to
+   * @param[in] data  Pointer to the event data
+   * @param[in] size  Size of the event data
+   * @return whether the event is sent successfully or not
+   */
+  bool SendEvent( int event, int ref, int refTo, const void *data, int size );
+
+private: // Class callbacks
+  /**
+   * Callback when server added
+   */
+  static Eina_Bool IpcServerAdd(void *data, int type, void *event);
+
+  /**
+   * Callback when server deleted
+   */
+  static Eina_Bool IpcServerDel(void *data, int type, void *event);
+
+  /**
+   * Callback when data available from server
+   */
+  static Eina_Bool IpcServerData(void *data, int type, void *event);
+
+private:
+  void CloseConnection();
+
+private:
+  typedef std::vector<Ecore_Event_Handler *> Handlers;
+
+  struct Service
+  {
+    const char *name;
+    int         num;
+    bool        isSystem;
+  };
+
+  Service           mService;
+  bool              mConnected;
+  Observer*         mObserver;
+  Ecore_Ipc_Server* mIpcServer;
+  Handlers          mIpcHandlers;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_CONNECTION_H_
diff --git a/adaptors/common/shared-file.cpp b/adaptors/common/shared-file.cpp
new file mode 100644 (file)
index 0000000..c62a663
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "shared-file.h"
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+
+#include <cstring>
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+SharedFile* SharedFile::New(const char* filename, int size, bool isSystem)
+{
+  SharedFile *sf = NULL;
+
+  sf = new SharedFile;
+
+  bool opened = sf->OpenFile( filename, size, isSystem );
+  if( !opened )
+  {
+    delete sf;
+    sf = NULL;
+  }
+  return sf;
+}
+
+SharedFile::SharedFile()
+: mFileDescriptor(-1),
+  mSize(0),
+  mAddress(NULL),
+  mFilename()
+{
+}
+
+SharedFile::~SharedFile()
+{
+  Close();
+}
+
+void SharedFile::Close()
+{
+  if( mAddress != NULL )
+  {
+    munmap( mAddress, mSize );
+    mAddress = NULL;
+  }
+
+  if( mFileDescriptor >= 0 )
+  {
+    close( mFileDescriptor );
+    mFileDescriptor = -1;
+  }
+}
+
+unsigned char* SharedFile::GetAddress()
+{
+  return static_cast<unsigned char *>( mAddress );
+}
+
+bool SharedFile::OpenFile(const char* filename, int size, bool isSystem)
+{
+  bool opened = false;
+  mode_t mode;
+
+  mode = S_IRUSR | S_IWUSR;
+  if( isSystem )
+  {
+    mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  }
+
+  mFileDescriptor = shm_open( filename, O_RDONLY, mode );
+
+  if( mFileDescriptor >= 0 )
+  {
+    mFilename = filename;
+
+    mSize = size;
+    mAddress = mmap( NULL, mSize, PROT_READ, MAP_SHARED, mFileDescriptor, 0 );
+
+    if( mAddress != MAP_FAILED )
+    {
+      opened = true;
+    }
+  }
+  return opened;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/common/shared-file.h b/adaptors/common/shared-file.h
new file mode 100644 (file)
index 0000000..81d48a7
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_SHARED_FILE_H__
+#define __DALI_INTERNAL_ADAPTOR_SHARED_FILE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class SharedFile
+{
+public:
+  /**
+   * Open an existing shared file for read/write
+   * @return The shared file, or NULL if a file could not be opened and mapped.
+   */
+  static SharedFile* New( const char* filename, int size, bool isSystem );
+
+  /**
+   * Constructor
+   */
+  SharedFile();
+
+  /**
+   * Destructor
+   */
+  virtual ~SharedFile();
+
+  /**
+   * Opens a file for read/write
+   * @return true if opened, false on error.
+   */
+  bool OpenFile( const char* filename, int size, bool isSystem );
+
+  /**
+   * Close the shared file
+   */
+  void Close();
+
+  /**
+   * Get the memory address of the shared file
+   * @return the memory address
+   */
+  unsigned char* GetAddress();
+
+private:
+  int         mFileDescriptor;
+  int         mSize;
+  void*       mAddress;
+  std::string mFilename;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_SHARED_FILE_H__
diff --git a/adaptors/common/singleton-service-impl.cpp b/adaptors/common/singleton-service-impl.cpp
new file mode 100644 (file)
index 0000000..8ab6bda
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <singleton-service-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#if defined(DEBUG_ENABLED)
+#include <tizen-logging.h>
+Debug::Filter* gSingletonServiceLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_SINGLETON_SERVICE" );
+
+// Need to define own macro as the log function is not installed when this object is created so no logging is shown with DALI_LOG_INFO at construction and destruction
+#define DALI_LOG_SINGLETON_SERVICE_DIRECT(level, message)                        \
+    if(gSingletonServiceLogFilter && gSingletonServiceLogFilter->IsEnabledFor(level)) { std::string string(message); Dali::TizenPlatform::LogMessage( Debug::DebugInfo, string );  }
+
+#define DALI_LOG_SINGLETON_SERVICE(level, format, args...) DALI_LOG_INFO(gSingletonServiceLogFilter, level, format, ## args )
+
+#else
+
+#define DALI_LOG_SINGLETON_SERVICE_DIRECT(level, message)
+#define DALI_LOG_SINGLETON_SERVICE(level, format, args...)
+
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// @todo Start using pthread_key_create if we want to avoid leaking the SingletonService on shutdown
+namespace
+{
+__thread SingletonService * gSingletonService = 0;
+} // unnamed namespace
+
+Dali::SingletonService SingletonService::New()
+{
+  Dali::SingletonService singletonService( new SingletonService );
+  return singletonService;
+}
+
+Dali::SingletonService SingletonService::Get()
+{
+  Dali::SingletonService singletonService;
+  if ( gSingletonService )
+  {
+    singletonService = Dali::SingletonService( gSingletonService );
+  }
+  return singletonService;
+}
+
+void SingletonService::Register( const std::type_info& info, BaseHandle singleton )
+{
+  if( singleton )
+  {
+    DALI_LOG_SINGLETON_SERVICE( Debug::General, "Singleton Added: %s\n", info.name() );
+    mSingletonContainer.insert( SingletonPair( info.name(), singleton ) );
+  }
+}
+
+void SingletonService::UnregisterAll( )
+{
+  mSingletonContainer.clear();
+}
+
+BaseHandle SingletonService::GetSingleton( const std::type_info& info ) const
+{
+  BaseHandle object;
+
+  SingletonConstIter iter = mSingletonContainer.find(info.name());
+  if( iter != mSingletonContainer.end() )
+  {
+    object = ( *iter ).second;
+  }
+
+  return object;
+}
+
+SingletonService::SingletonService()
+: mSingletonContainer()
+{
+  // Can only have one instance of SingletonService
+  DALI_ASSERT_ALWAYS( !gSingletonService && "Only one instance of SingletonService is allowed");
+
+  gSingletonService = this;
+
+  DALI_LOG_SINGLETON_SERVICE_DIRECT( Debug::Concise, "SingletonService Created\n" );
+}
+
+SingletonService::~SingletonService()
+{
+  gSingletonService = 0;
+
+  DALI_LOG_SINGLETON_SERVICE_DIRECT( Debug::Concise, "SingletonService Destroyed\n" );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/adaptors/common/singleton-service-impl.h b/adaptors/common/singleton-service-impl.h
new file mode 100644 (file)
index 0000000..e5d623c
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef __DALI_INTERNAL_SINGLETON_SERVICE_H__
+#define __DALI_INTERNAL_SINGLETON_SERVICE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/common/map-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class SingletonService : public Dali::BaseObject
+{
+public:
+
+  /**
+   * Create a SingletonService.
+   * This should only be called once by the Application class.
+   * @return A newly created SingletonService.
+   */
+  static Dali::SingletonService New();
+
+  /**
+   * @copydoc Dali::SingletonService::Get()
+   */
+  static Dali::SingletonService Get();
+
+  /**
+   * @copydoc Dali::SingletonService::Register()
+   */
+  void Register( const std::type_info& info, BaseHandle singleton );
+
+  /**
+   * @copydoc Dali::SingletonService::UnregisterAll()
+   */
+  void UnregisterAll();
+
+  /**
+   * @copydoc Dali::SingletonService::GetSingleton()
+   */
+  BaseHandle GetSingleton( const std::type_info& info ) const;
+
+private:
+
+  /**
+   * Private Constructor
+   * @see SingletonService::New()
+   */
+  SingletonService();
+
+  /**
+   * Virtual Destructor
+   */
+  virtual ~SingletonService();
+
+  // Undefined
+  SingletonService( const SingletonService& );
+  SingletonService& operator=( SingletonService& );
+
+private:
+
+  typedef std::pair<std::string, BaseHandle> SingletonPair;
+  typedef std::map<std::string, BaseHandle>  SingletonContainer;
+  typedef SingletonContainer::const_iterator SingletonConstIter;
+
+  SingletonContainer mSingletonContainer; ///< The container to look up singleton by its type name
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::SingletonService& GetImplementation(Dali::SingletonService& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SingletonService handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::SingletonService&>(handle);
+}
+
+inline const Internal::Adaptor::SingletonService& GetImplementation(const Dali::SingletonService& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SingletonService handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::SingletonService&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_SINGLETON_SERVICE_H__
diff --git a/adaptors/common/sound-player-impl.cpp b/adaptors/common/sound-player-impl.cpp
new file mode 100644 (file)
index 0000000..37ba5de
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <sound-player-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+const char* const SIGNAL_SOUND_PLAY_FINISHED = "sound-play-finished";
+
+// Type Registration
+Dali::BaseHandle GetInstance()
+{
+  return SoundPlayer::Get();
+}
+
+Dali::TypeRegistration SOUND_PLAYER_TYPE( typeid(Dali::SoundPlayer), typeid(Dali::BaseHandle), GetInstance );
+
+Dali::SignalConnectorType SIGNAL_CONNECTOR_1( SOUND_PLAYER_TYPE, SIGNAL_SOUND_PLAY_FINISHED, Dali::Internal::Adaptor::SoundPlayer::DoConnectSignal );
+
+} // unnamed namespace
+
+Dali::SoundPlayer SoundPlayer::New()
+{
+  Dali::SoundPlayer player = Dali::SoundPlayer( new SoundPlayer() );
+  return player;
+}
+
+Dali::SoundPlayer SoundPlayer::Get()
+{
+  Dali::SoundPlayer player;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::SoundPlayer ) );
+    if ( handle )
+    {
+      // If so, downcast the handle
+      player = Dali::SoundPlayer( dynamic_cast< SoundPlayer* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      player = Dali::SoundPlayer( New() );
+      service.Register( typeid( player ), player );
+    }
+  }
+
+  return player;
+}
+
+int SoundPlayer::PlaySound( const std::string fileName )
+{
+  return mPlugin.PlaySound( fileName );
+}
+
+void SoundPlayer::Stop( int handle )
+{
+  mPlugin.StopSound( handle );
+}
+
+SoundPlayer::SoundPlayFinishedSignalType& SoundPlayer::SoundPlayFinishedSignal()
+{
+  return mSoundPlayFinishedSignal;
+}
+
+bool SoundPlayer::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  SoundPlayer* player = dynamic_cast<SoundPlayer*>( object );
+
+  if( player && ( SIGNAL_SOUND_PLAY_FINISHED == signalName ) )
+  {
+    player->SoundPlayFinishedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+SoundPlayer::SoundPlayer()
+: mPlugin( FeedbackPluginProxy::DEFAULT_OBJECT_NAME )
+{
+}
+
+SoundPlayer::~SoundPlayer()
+{
+}
+
+void SoundPlayer::EmitSoundPlayFinishedSignal()
+{
+  // Emit SoundPlayFinished signal
+
+  if ( !mSoundPlayFinishedSignal.Empty() )
+  {
+    Dali::SoundPlayer handle( this );
+    mSoundPlayFinishedSignal.Emit( handle );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/sound-player-impl.h b/adaptors/common/sound-player-impl.h
new file mode 100644 (file)
index 0000000..f30245a
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef __DALI_INTERNAL_SOUND_PLAYER_H__
+#define __DALI_INTERNAL_SOUND_PLAYER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <sound-player.h>
+#include <feedback/feedback-plugin-proxy.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Plays haptic effects.
+ */
+class SoundPlayer : public Dali::BaseObject
+{
+
+public:
+
+  typedef Dali::SoundPlayer::SoundPlayFinishedSignalType SoundPlayFinishedSignalType;
+
+  /**
+   * Create a SoundPlayer.
+   * @return A newly created SoundPlayer.
+   */
+  static Dali::SoundPlayer New();
+
+  /**
+   * Retrieve a handle to the SoundPlayer. This creates an instance if none has been created.
+   * @return A handle to the SoundPlayer.
+   */
+  static Dali::SoundPlayer Get();
+
+  /**
+   * @copydoc Dali::SoundPlayer::PlaySound()
+   */
+  int PlaySound(const std::string fileName);
+
+  /**
+   * @copydoc Dali::SoundPlayer::Stop()
+   */
+  void Stop(int handle);
+
+  /**
+   * @copydoc Dali::SoundPlayer::SoundPlayFinishedSignal()
+   */
+  SoundPlayFinishedSignalType& SoundPlayFinishedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * Private Constructor; see also soundPlayer::New()
+   * @param[in]  soundPlayer  The public sound player class
+   */
+  SoundPlayer();
+
+  /**
+   * Destructor
+   */
+  virtual ~SoundPlayer();
+
+  /**
+   * Emits the SoundPlayFinished signal.
+   */
+  void EmitSoundPlayFinishedSignal();
+
+  // Undefined
+  SoundPlayer(const SoundPlayer&);
+
+  // Undefined
+  SoundPlayer& operator=(SoundPlayer&);
+
+private:
+
+  FeedbackPluginProxy mPlugin;
+  SoundPlayFinishedSignalType mSoundPlayFinishedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::SoundPlayer& GetImplementation(Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::SoundPlayer& GetImplementation(const Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_SOUND_PLAYER_H__
diff --git a/adaptors/common/style-monitor-impl.cpp b/adaptors/common/style-monitor-impl.cpp
new file mode 100644 (file)
index 0000000..8e47cfe
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "style-monitor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <fstream>
+#include <sstream>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_STYLE_MONITOR");
+#endif
+
+BaseHandle Create()
+{
+  BaseHandle handle( StyleMonitor::Get() );
+
+  if ( !handle && Adaptor::IsAvailable() )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
+      Dali::StyleMonitor styleMonitor = Dali::StyleMonitor( new StyleMonitor( adaptorImpl.GetPlatformAbstraction() ) );
+      service.Register( typeid( styleMonitor ), styleMonitor );
+      handle = styleMonitor;
+    }
+  }
+
+  return handle;
+}
+TypeRegistration STYLE_MONITOR_TYPE( typeid(Dali::StyleMonitor), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+/**
+ * Use font client to get the system default font family
+ * @param[in] fontClient handle to font client
+ * @param[out] fontFamily string representing font family
+ */
+void GetSystemDefaultFontFamily( TextAbstraction::FontClient& fontClient, std::string& fontFamily )
+{
+  TextAbstraction::FontDescription defaultFontDescription;
+  if ( fontClient )
+  {
+    fontClient.GetDefaultPlatformFontDescription( defaultFontDescription );
+    fontFamily = defaultFontDescription.family;
+  }
+}
+
+} // unnamed namespace
+
+Dali::StyleMonitor StyleMonitor::Get()
+{
+  Dali::StyleMonitor styleMonitor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::StyleMonitor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      styleMonitor = Dali::StyleMonitor( dynamic_cast< StyleMonitor* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return styleMonitor;
+}
+
+StyleMonitor::StyleMonitor(Integration::PlatformAbstraction& platformAbstraction)
+: mPlatformAbstraction(platformAbstraction),
+  mDefaultFontSize(-1)
+{
+  mfontClient = TextAbstraction::FontClient::Get();
+  GetSystemDefaultFontFamily( mfontClient, mDefaultFontFamily );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::StyleMonitor::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str() );
+  mDefaultFontSize = mPlatformAbstraction.GetDefaultFontSize();
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+void StyleMonitor::StyleChanged( StyleChange::Type styleChange )
+{
+  switch ( styleChange )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      GetSystemDefaultFontFamily( mfontClient, mDefaultFontFamily );
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::StyleChanged::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str() );
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      mDefaultFontSize = mPlatformAbstraction.GetDefaultFontSize();
+      break;
+    }
+
+    case StyleChange::THEME_CHANGE:
+    {
+      break;
+    }
+  }
+
+  EmitStyleChangeSignal(styleChange);
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return mDefaultFontFamily;
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return mDefaultFontStyle;
+}
+
+int StyleMonitor::GetDefaultFontSize() const
+{
+  return mDefaultFontSize;
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return mUserDefinedThemeFilePath;
+}
+
+void StyleMonitor::SetTheme(const std::string& path)
+{
+  mUserDefinedThemeFilePath = path;
+  EmitStyleChangeSignal( StyleChange::THEME_CHANGE );
+}
+
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  bool retval( false );
+  std::ifstream in( filename.c_str(), std::ios::in );
+  if( in )
+  {
+    std::stringstream buffer;
+    buffer << in.rdbuf();
+
+    output = buffer.str();
+
+    in.close();
+    retval = true;
+  }
+  return retval;
+}
+
+Dali::StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
+{
+  return mStyleChangeSignal;
+}
+
+void StyleMonitor::EmitStyleChangeSignal( StyleChange::Type styleChange )
+{
+  if( !mStyleChangeSignal.Empty() )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::EmitStyleChangeSignal\n" );
+    Dali::StyleMonitor handle( this );
+    mStyleChangeSignal.Emit( handle, styleChange );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/style-monitor-impl.h b/adaptors/common/style-monitor-impl.h
new file mode 100644 (file)
index 0000000..ed448d6
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef __DALI_INTERNAL_STYLE_MONITOR_H__
+#define __DALI_INTERNAL_STYLE_MONITOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <style-monitor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This holds the platform's style information.
+ * It provides a signal when any aspect of the default style changes on the device.
+ */
+class StyleMonitor : public BaseObject
+{
+public:
+
+  // Creation & Destruction
+
+  /**
+   * Constructor.
+   * @param[in]  platformAbstraction  The platform abstraction.
+   */
+  StyleMonitor(Integration::PlatformAbstraction& platformAbstraction);
+
+  /**
+   * Retrieve the initialized instance of the StyleMonitor.
+   * @return Handle to StyleMonitor.
+   */
+  static Dali::StyleMonitor Get();
+
+  // Style Change Notifications
+
+  /**
+   * Informs the Style Monitor that the style has changed.
+   * @param[in]  styleChange  The details of the change.
+   */
+  void StyleChanged( StyleChange::Type styleChange );
+
+  // Style Information
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontFamily() const
+   */
+  std::string GetDefaultFontFamily() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontStyle() const
+   */
+  std::string GetDefaultFontStyle() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontSize() const
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetTheme() const
+   */
+  const std::string& GetTheme() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::SetTheme()
+   */
+  void SetTheme(const std::string& themeFilePath);
+
+  /**
+   * @copydoc Dali::StyleMonitor::LoadThemeFile()
+   */
+  bool LoadThemeFile( const std::string& filename, std::string& output );
+
+  // Signals
+
+  /**
+   * @copydoc Dali::StyleMonitor::StyleChangeSignal()
+   */
+  Dali::StyleMonitor::StyleChangeSignalType& StyleChangeSignal();
+
+protected:
+
+  /**
+   * Virtual Destructor.
+   */
+  virtual ~StyleMonitor();
+
+private:
+
+  /**
+   * Emit the style change signal.
+   * @param[in]  styleChange  The details of the style change
+   */
+  inline void EmitStyleChangeSignal( StyleChange::Type styleChange );
+
+private:
+
+  Dali::StyleMonitor::StyleChangeSignalType mStyleChangeSignal; ///< Emitted when the style changes
+
+  Integration::PlatformAbstraction& mPlatformAbstraction; ///< Reference to the PlatformAbstraction (for retrieving defaults)
+
+  TextAbstraction::FontClient mfontClient;
+  std::string mDefaultFontFamily;        ///< The system default font family
+  std::string mDefaultFontStyle;         ///< The default font style
+  std::string mUserDefinedThemeFilePath; ///< String containing the user defined theme file path
+  int mDefaultFontSize;                  ///< The default accessibility font size e.g. 0 is smallest
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::StyleMonitor& GetImplementation(Dali::StyleMonitor& monitor)
+{
+  DALI_ASSERT_ALWAYS(monitor && "Monitor handle is empty");
+  BaseObject& handle = monitor.GetBaseObject();
+  return static_cast<Internal::Adaptor::StyleMonitor&>(handle);
+}
+
+inline const Internal::Adaptor::StyleMonitor& GetImplementation(const Dali::StyleMonitor& monitor)
+{
+  DALI_ASSERT_ALWAYS(monitor && "Monitor handle is empty");
+  const BaseObject& handle = monitor.GetBaseObject();
+  return static_cast<const Internal::Adaptor::StyleMonitor&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_STYLE_MONITOR_H__
diff --git a/adaptors/common/system-settings.cpp b/adaptors/common/system-settings.cpp
new file mode 100644 (file)
index 0000000..59ae1c3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "system-settings.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/system-settings.h b/adaptors/common/system-settings.h
new file mode 100644 (file)
index 0000000..7ebb352
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef __DALI_INTERNAL_SYSTEM_SETTINGS_H___
+#define __DALI_INTERNAL_SYSTEM_SETTINGS_H___
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// Get SYSTEM_SETTINGS_KEY_TAP_AND_HOLD_DELAY from system setting if available
+int GetLongPressTime( int defaultTime );
+
+// Get ELM_ACCESS_ACTION_OVER from Elementary if available
+int GetElmAccessActionOver();
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_SYSTEM_SETTINGS_H___
diff --git a/adaptors/common/system-trace.cpp b/adaptors/common/system-trace.cpp
new file mode 100644 (file)
index 0000000..ff84a83
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "system-trace.h"
+
+// EXTERNAL HEADERS
+#include <string>
+#include <dali/devel-api/common/hash.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+#ifdef ENABLE_TTRACE
+#include <ttrace.h>
+#else
+
+// Emulate trace calls if ttrace isn't available
+namespace
+{
+const int TTRACE_TAG_GRAPHICS = 1;
+
+void traceAsyncBegin(int tag, int cookie, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "AsyncBegin: %s : cookie %d\n", name, cookie );
+}
+void traceAsyncEnd(int tag, int cookie, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "AsyncEnd: %s : cookie %d\n", name, cookie );
+}
+void traceMark(int tag, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "Marker: %s \n", name);
+}
+} // un-named namespace
+#endif
+
+namespace
+{
+
+int GetCookie( const std::string& description, std::string& markerName )
+{
+  // description holds the marker name and postfix of _START or _END
+  std::size_t pos = description.find("_START");
+  if( pos == std::string::npos )
+  {
+    pos = description.find("_END");
+  }
+  if( !pos )
+  {
+    // if this asserts then check the postfix strings in StatContext.cpp for
+    // custom markers and performance-marker.cpp for built-in markers
+    DALI_ASSERT_DEBUG(0);
+  }
+  markerName = description.substr( 0, pos );
+
+  std::size_t hash =  Dali::CalculateHash( markerName.c_str() );
+  return static_cast<int>( hash );
+}
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+SystemTrace::SystemTrace()
+{
+}
+SystemTrace::~SystemTrace()
+{
+}
+
+void SystemTrace::Trace( const PerformanceMarker& marker, const std::string& traceMessage )
+{
+  PerformanceMarker::MarkerEventType eventType = marker.GetEventType();
+
+  if( eventType == PerformanceMarker::SINGLE_EVENT )
+  {
+    traceMark( TTRACE_TAG_GRAPHICS, traceMessage.c_str() );
+    return;
+  }
+
+  // DALi is multi-threaded so timed events will occur asynchronously
+  std::string markerName;
+
+  int cookie = GetCookie(traceMessage, markerName );
+
+  if( eventType == PerformanceMarker::START_TIMED_EVENT )
+  {
+    traceAsyncBegin( TTRACE_TAG_GRAPHICS, cookie,  markerName.c_str() );
+  }
+  else
+  {
+    traceAsyncEnd( TTRACE_TAG_GRAPHICS, cookie,  markerName.c_str() );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
diff --git a/adaptors/common/system-trace.h b/adaptors/common/system-trace.h
new file mode 100644 (file)
index 0000000..32de01e
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H__
+#define __DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <base/interfaces/trace-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Concrete System  Tracing Interface.
+ * Used to log trace messages to the system using ttrace
+ *
+ */
+class SystemTrace : public TraceInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  SystemTrace();
+
+  /**
+   * Destructor
+   */
+  virtual ~SystemTrace();
+
+  /**
+   * @copydoc KernelTracerInterface::KernelTrace()
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H__
diff --git a/adaptors/common/timer-impl.h b/adaptors/common/timer-impl.h
new file mode 100644 (file)
index 0000000..e8bc456
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef __DALI_INTERNAL_TIMER_H__
+#define __DALI_INTERNAL_TIMER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/timer-interface.h>
+#include <timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Timer;
+
+typedef IntrusivePtr<Timer> TimerPtr;
+
+/**
+ * Implementation of the timer
+ */
+class Timer : public BaseObject, public TimerInterface
+{
+public:
+  static TimerPtr New( unsigned int milliSec );
+
+  /**
+   * Constructor
+   * @param[in]  milliSec  Interval in milliseconds.
+   */
+  Timer( unsigned int milliSec );
+
+  /**
+   * Destructor.
+   */
+  virtual ~Timer();
+
+public:
+
+  /**
+   * @copydoc Dali::Timer::Start()
+   */
+  virtual void Start();
+
+  /**
+   * @copydoc Dali::Timer::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc Dali::Timer::SetInterval()
+   */
+  virtual void SetInterval( unsigned int interval );
+
+  /**
+   * @copydoc Dali::Timer::GetInterval()
+   */
+  virtual unsigned int GetInterval() const;
+
+  /**
+   * @copydoc Dali::Timer::IsRunning()
+   */
+  virtual bool IsRunning() const;
+
+  /**
+   * Tick
+   */
+  bool Tick();
+
+public: // Signals
+
+  Dali::Timer::TimerSignalType& TickSignal();
+
+private: // Implementation
+
+  // not implemented
+  Timer( const Timer& );
+  Timer& operator=( const Timer& );
+
+private: // Data
+
+  Dali::Timer::TimerSignalType mTickSignal;
+
+  // To hide away implementation details
+  struct Impl;
+  Impl* mImpl;
+};
+
+inline Timer& GetImplementation(Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Timer&>(handle);
+}
+
+inline const Timer& GetImplementation(const Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  const BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Timer&>(handle);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TIMER_H__
diff --git a/adaptors/common/trigger-event-factory.cpp b/adaptors/common/trigger-event-factory.cpp
new file mode 100644 (file)
index 0000000..68b3614
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "trigger-event-factory.h"
+
+// INTERNAL INCLUDES
+#include <trigger-event.h>
+
+namespace Dali
+{
+
+TriggerEventInterface* TriggerEventFactory::CreateTriggerEvent( CallbackBase* callback,  TriggerEventInterface::Options options )
+{
+  return new Internal::Adaptor::TriggerEvent( callback, options );
+}
+
+void TriggerEventFactory::DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface )
+{
+  Internal::Adaptor::TriggerEvent* triggerEvent( static_cast<Internal::Adaptor::TriggerEvent *>(triggerEventInterface) );
+  delete triggerEvent;
+}
+
+} // namespace Dali
diff --git a/adaptors/common/trigger-event.cpp b/adaptors/common/trigger-event.cpp
new file mode 100644 (file)
index 0000000..c4bb760
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "trigger-event.h"
+
+// EXTERNAL INCLUDES
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+#include <file-descriptor-monitor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TriggerEvent::TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options )
+: mFileDescriptorMonitor( NULL ),
+  mCallback( callback ),
+  mFileDescriptor( -1 ),
+  mOptions( options )
+{
+  // Create accompanying file descriptor.
+  mFileDescriptor = eventfd(0, EFD_NONBLOCK);
+  if (mFileDescriptor >= 0)
+  {
+    // Now Monitor the created event file descriptor
+    mFileDescriptorMonitor = new FileDescriptorMonitor( mFileDescriptor, MakeCallback( this, &TriggerEvent::Triggered ) );
+  }
+  else
+  {
+    DALI_LOG_ERROR("Unable to create TriggerEvent File descriptor\n");
+  }
+}
+
+TriggerEvent::~TriggerEvent()
+{
+  delete mFileDescriptorMonitor;
+  delete mCallback;
+
+  if (mFileDescriptor >= 0)
+  {
+    close(mFileDescriptor);
+    mFileDescriptor = 0;
+  }
+}
+
+void TriggerEvent::Trigger()
+{
+  if (mFileDescriptor >= 0)
+  {
+    // Increment event counter by 1.
+    // Writing to the file descriptor triggers the Dispatch() method in the other thread
+    // (if in multi-threaded environment).
+
+    uint64_t data = 1;
+    int size = write(mFileDescriptor, &data, sizeof(uint64_t));
+
+    if (size != sizeof(uint64_t))
+    {
+      DALI_LOG_ERROR("Unable to write to UpdateEvent File descriptor\n");
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING("Attempting to write to an invalid file descriptor\n");
+  }
+}
+
+void TriggerEvent::Triggered()
+{
+  // Reading from the file descriptor resets the event counter, we can ignore the count.
+  uint64_t receivedData;
+  size_t size;
+  size = read(mFileDescriptor, &receivedData, sizeof(uint64_t));
+  if (size != sizeof(uint64_t))
+  {
+    DALI_LOG_WARNING("Unable to read to UpdateEvent File descriptor\n");
+  }
+
+  // Call the connected callback
+  CallbackBase::Execute( *mCallback );
+
+  //check if we should delete ourselves after the trigger
+  if( mOptions == TriggerEventInterface::DELETE_AFTER_TRIGGER )
+  {
+    delete this;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/trigger-event.h b/adaptors/common/trigger-event.h
new file mode 100644 (file)
index 0000000..8de3d73
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __DALI_INTERNAL_TRIGGER_EVENT_H__
+#define __DALI_INTERNAL_TRIGGER_EVENT_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <trigger-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class FileDescriptorMonitor;
+
+/**
+ * The TriggerEvent class is used to send events between threads.  For example, this can be used
+ * to wake up one thread from another thread.
+ *
+ * Typically, these should be created in the application thread.
+ *
+ * The observer will be informed whenever the event is triggered.
+ *
+ * The implementation of TriggerEvent uses an event file descriptor.
+ */
+class TriggerEvent : public TriggerEventInterface
+{
+public:
+
+  /**
+   * Constructor
+   * Creates an event file descriptor and starts a GSource which reads from the file
+   * descriptor when there is data.
+   *
+   * @param[in] callback The callback to call
+   * @param[in] options Trigger event options.
+   * @note The ownership of callback is taken by this class.
+   */
+  TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options );
+
+  /**
+   * Destructor
+   */
+  ~TriggerEvent();
+
+public:
+
+  /**
+   * Triggers the event.
+   *
+   * This can be called from one thread in order to wake up another thread.
+   */
+  void Trigger();
+
+private:
+
+  /**
+   * Called when our event file descriptor has been written to.
+   */
+  void Triggered();
+
+private:
+
+  struct Source;
+
+private:
+
+  FileDescriptorMonitor* mFileDescriptorMonitor;
+  CallbackBase* mCallback;
+  int mFileDescriptor;
+  TriggerEventInterface::Options mOptions;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TRIGGER_EVENT_H__
diff --git a/adaptors/common/virtual-keyboard-impl.cpp b/adaptors/common/virtual-keyboard-impl.cpp
new file mode 100644 (file)
index 0000000..9fca891
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "virtual-keyboard-impl.h"
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <locale-utils.h>
+#include <imf-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_VIRTUAL_KEYBOARD");
+#endif
+
+#define TOKEN_STRING(x) #x
+
+//forward declarations
+void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value );
+void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value );
+
+// Signals
+Dali::VirtualKeyboard::StatusSignalType gKeyboardStatusSignal;
+Dali::VirtualKeyboard::VoidSignalType   gKeyboardResizeSignal;
+Dali::VirtualKeyboard::VoidSignalType   gKeyboardLanguageChangedSignal;
+
+void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  switch (value)
+  {
+    case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ECORE_IMF_INPUT_PANEL_STATE_SHOW\n" );
+
+      gKeyboardStatusSignal.Emit( true );
+
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ECORE_IMF_INPUT_PANEL_STATE_HIDE\n" );
+
+      gKeyboardStatusSignal.Emit( false );
+
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
+    default:
+    {
+      // Do nothing
+      break;
+    }
+  }
+}
+
+void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VKB InputPanelLanguageChangeCallback" );
+
+  // Emit the signal that the language has changed
+  gKeyboardLanguageChangedSignal.Emit();
+}
+
+void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VKB InputPanelGeometryChangedCallback\n" );
+
+  // Emit signal that the keyboard is resized
+  gKeyboardResizeSignal.Emit();
+}
+
+} // unnamed namespace
+
+void ConnectCallbacks( Ecore_IMF_Context *imfContext )
+{
+  if( imfContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ConnectPanelCallbacks\n" );
+
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback,     NULL );
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback,  NULL );
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, NULL );
+  }
+}
+
+void DisconnectCallbacks( Ecore_IMF_Context *imfContext )
+{
+  if( imfContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "VKB DisconnectPanelCallbacks\n" );
+
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
+  }
+}
+
+void Show()
+{
+  Dali::ImfManager imfManager = ImfManager::Get(); // Create ImfManager instance (if required) to show the keyboard
+  Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+  if( imfContext )
+  {
+    ecore_imf_context_input_panel_show( imfContext );
+  }
+}
+
+void Hide()
+{
+  if( ImfManager::IsAvailable() /* We do not want to create an ImfManager instance*/ )
+  {
+    Dali::ImfManager imfManager = ImfManager::Get();
+    Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+    if( imfContext )
+    {
+      ecore_imf_context_input_panel_hide( imfContext );
+    }
+  }
+}
+
+bool IsVisible()
+{
+  if( ImfManager::IsAvailable() /* We do not want to create an ImfManager instance */ )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "IsVisible\n" );
+
+    Dali::ImfManager imfManager = ImfManager::Get();
+    Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+    if ( imfContext )
+    {
+      if (ecore_imf_context_input_panel_state_get(imfContext) == ECORE_IMF_INPUT_PANEL_STATE_SHOW ||
+          ecore_imf_context_input_panel_state_get(imfContext) == ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW)
+      {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+  using namespace InputMethod; // Allows exclusion of namespace in TOKEN_STRING.
+
+  for ( unsigned int i = 0, count = settingsMap.Count(); i < count; ++i )
+  {
+    std::string key = settingsMap.GetKey( i );
+    Property::Value item = settingsMap.GetValue(i);
+
+    if ( key == TOKEN_STRING( ACTION_BUTTON ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        VirtualKeyboard::SetReturnKeyType( static_cast<InputMethod::ActionButton>(value) );
+      }
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Provided Settings Key not supported\n" );
+    }
+   }
+}
+
+void EnablePrediction(const bool enable)
+{
+  Dali::ImfManager imfManager = ImfManager::Get(); // Create ImfManager instance (if required) when enabling prediction
+  Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+  if ( imfContext )
+  {
+    ecore_imf_context_prediction_allow_set( imfContext, (enable)? EINA_TRUE : EINA_FALSE);
+  }
+}
+
+bool IsPredictionEnabled()
+{
+  if ( ImfManager::IsAvailable() /* We do not want to create an instance of ImfManger */ )
+  {
+    Dali::ImfManager imfManager = ImfManager::Get();
+    Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+    if ( imfContext )
+    {
+      // predictive text is enabled.
+      if ( ecore_imf_context_input_panel_enabled_get( imfContext ) == EINA_TRUE )
+      {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  int xPos, yPos, width, height;
+
+  width = height = xPos = yPos = 0;
+  Dali::ImfManager imfManager = ImfManager::Get(); // Create ImfManager instance (if required) as we may need to do some size related setup in the application
+  Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+  if( imfContext )
+  {
+    ecore_imf_context_input_panel_geometry_get(imfContext, &xPos, &yPos, &width, &height);
+  }
+  else
+  {
+    DALI_LOG_WARNING("VKB Unable to get IMF Context so GetSize unavailable\n");
+    // return 0 as real size unknown.
+  }
+
+  return Rect<int>(xPos,yPos,width,height);
+}
+
+Dali::VirtualKeyboard::StatusSignalType& StatusChangedSignal()
+{
+  return gKeyboardStatusSignal;
+}
+
+Dali::VirtualKeyboard::VoidSignalType& ResizedSignal()
+{
+  return gKeyboardResizeSignal;
+}
+
+Dali::VirtualKeyboard::VoidSignalType& LanguageChangedSignal()
+{
+  return gKeyboardLanguageChangedSignal;
+}
+
+Dali::VirtualKeyboard::TextDirection GetTextDirection()
+{
+  Dali::VirtualKeyboard::TextDirection direction ( Dali::VirtualKeyboard::LeftToRight );
+
+  if ( ImfManager::IsAvailable() /* We do not want to create an instance of ImfManager */ )
+  {
+    Dali::ImfManager imfManager = ImfManager::Get();
+
+    if ( imfManager )
+    {
+      Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+      if ( imfContext )
+      {
+        char* locale( NULL );
+        ecore_imf_context_input_panel_language_locale_get( imfContext, &locale );
+
+        if ( locale )
+        {
+          direction = Locale::GetTextDirection( std::string( locale ) );
+          free( locale );
+        }
+      }
+    }
+  }
+  return direction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/common/virtual-keyboard-impl.h b/adaptors/common/virtual-keyboard-impl.h
new file mode 100644 (file)
index 0000000..6acd185
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef __DALI_INTERNAL_VIRTUAL_KEYBOARD_H__
+#define __DALI_INTERNAL_VIRTUAL_KEYBOARD_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_IMF.h>
+
+// INTERNAL INCLUDES
+#include <virtual-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the virtual keyboard namespace
+ */
+namespace VirtualKeyboard
+{
+
+/**
+ * Connect the virtual keyboard callbacks.
+ * To get the virtual keyboard callbacks then you have to connect these callback.
+ * If you don't connect callbacks, you can't get virtual keyboard signals.
+ * The signals are StatusChangedSignal, ResizedSignal and LanguageChangedSignal.
+ */
+void ConnectCallbacks( Ecore_IMF_Context *imfContext );
+
+/**
+ * Disconnect the virtual keyboard callbacks.
+ * The signals are StatusChangedSignal, ResizedSignal and LanguageChangedSignal.
+ */
+void DisconnectCallbacks( Ecore_IMF_Context *imfContext );
+
+/**
+ * @copydoc Dali::VirtualKeyboard::Show()
+ */
+void Show();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::Hide()
+ */
+void Hide();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::IsVisible()
+ */
+bool IsVisible();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::ApplySettings()
+ */
+void ApplySettings( const Property::Map& settingsMap );
+
+/**
+ * @copydoc Dali::VirtualKeyboard::SetReturnKeyType()
+ */
+void SetReturnKeyType( const Dali::InputMethod::ActionButton type );
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetReturnKeyType()
+ */
+Dali::InputMethod::ActionButton GetReturnKeyType();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::EnablePrediction()
+ */
+void EnablePrediction(const bool enable);
+
+/**
+ * @copydoc Dali::VirtualKeyboard::IsPredictionEnabled()
+ */
+bool IsPredictionEnabled();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetSizeAndPosition()
+ */
+Rect<int> GetSizeAndPosition();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::RotateKeyboard()
+ */
+void RotateTo(int angle);
+
+/**
+ * @copydox Dali::VirtualKeyboard::StatusChangedSignal()
+ */
+Dali::VirtualKeyboard::StatusSignalType& StatusChangedSignal();
+
+/**
+ * @copydox Dali::VirtualKeyboard::ResizedSignal()
+ */
+Dali::VirtualKeyboard::VoidSignalType& ResizedSignal();
+
+/**
+ * @copydox Dali::VirtualKeyboard::LanguageChangedSignal()
+ */
+Dali::VirtualKeyboard::VoidSignalType& LanguageChangedSignal();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetTextDirection
+ */
+Dali::VirtualKeyboard::TextDirection GetTextDirection();
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_VIRTUAL_KEYBOARD_H__
diff --git a/adaptors/common/vsync-monitor.h b/adaptors/common/vsync-monitor.h
new file mode 100644 (file)
index 0000000..f990d7b
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __DALI_INTERNAL_VSYNC_MONITOR_IMPL_H__
+#define __DALI_INTERNAL_VSYNC_MONITOR_IMPL_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <xf86drm.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/vsync-monitor-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Tizen interface for monitoring VSync
+ */
+class VSyncMonitor : public VSyncMonitorInterface
+{
+public:
+  /**
+   * Default constructor
+   */
+  VSyncMonitor();
+
+  /**
+   * Destructor
+   */
+  virtual ~VSyncMonitor();
+
+public:
+
+  /**
+   * Set the use hardware flag
+   * @param[in] useHardware The new state for the use hardware flag.
+   */
+  void SetUseHardwareVSync( bool useHardware );
+
+  /**
+   * Set whether the vsync hardware is available.
+   * (This is public to allow callback method to work...)
+   */
+  void SetHardwareVSyncAvailable(bool available);
+
+private: // From Dali::Internal::Adaptor::VSyncMonitorInterface
+
+  /**
+   * copydoc Dali::Internal::Adaptor::VSyncMonitorInterface::Initialize
+   */
+  virtual void Initialize();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::VSyncMonitorInterface::Terminate
+   */
+  virtual void Terminate();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::VSyncMonitorInterface::UseHardware
+   */
+  virtual bool UseHardware();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::VSyncMonitorInterface::DoSync
+   */
+  virtual bool DoSync( unsigned int& frameNumber, unsigned int& seconds, unsigned int& microseconds );
+
+private:
+
+  int       mFileDescriptor;  ///< DRM dev node file descriptor
+  drmVBlank mVBlankInfo;
+  // NOTE cannot use booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
+  unsigned int mUseHardwareVSync; ///< Whether to use hardware vsync
+  unsigned int mHardwareVSyncAvailable; ///< Whether hardware vsync is available
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_VSYNC_MONITOR_IMPL_H__
diff --git a/adaptors/common/window-impl.h b/adaptors/common/window-impl.h
new file mode 100644 (file)
index 0000000..d1403b5
--- /dev/null
@@ -0,0 +1,315 @@
+#ifndef __DALI_INTERNAL_WINDOW_H__
+#define __DALI_INTERNAL_WINDOW_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <base/lifecycle-observer.h>
+#include <adaptor-impl.h>
+#include <indicator-impl.h>
+#include <window.h>
+#include <orientation.h>
+#include <render-surface.h>
+#include <drag-and-drop-detector.h>
+
+namespace Dali
+{
+class Adaptor;
+class RenderSurface;
+
+namespace Integration
+{
+class SystemOverlay;
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Indicator;
+class Orientation;
+
+class Window;
+typedef IntrusivePtr<Window> WindowPtr;
+typedef IntrusivePtr<Orientation> OrientationPtr;
+
+/**
+ * Window provides a surface to render onto with orientation & indicator properties.
+ */
+class Window : public Dali::BaseObject, public Indicator::Observer, public LifeCycleObserver
+{
+public:
+  typedef Dali::Window::IndicatorSignalType IndicatorSignalType;
+  typedef Signal< void () > SignalType;
+
+  /**
+   * Create a new Window. This should only be called once by the Application class
+   * @param[in] windowPosition The position and size of the window
+   * @param[in] name The window title
+   * @param[in] className The window class name
+   * @param[in] isTransparent Whether window is transparent
+   * @return A newly allocated Window
+   */
+  static Window* New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  /**
+   * Pass the adaptor back to the overlay. This allows the window to access Core's overlay.
+   * @param[in] adaptor An initialized adaptor
+   */
+  void SetAdaptor(Dali::Adaptor& adaptor);
+
+  /**
+   * Get the window surface
+   * @return The render surface
+   */
+  RenderSurface* GetSurface();
+
+  /**
+   * @copydoc Dali::Window::ShowIndicator()
+   */
+  void ShowIndicator( Dali::Window::IndicatorVisibleMode visibleMode );
+
+  /**
+   * @copydoc Dali::Window::SetIndicatorBgOpacity()
+   */
+  void SetIndicatorBgOpacity( Dali::Window::IndicatorBgOpacity opacity );
+
+  /**
+   * @copydoc Dali::Window::RotateIndicator()
+   */
+  void RotateIndicator( Dali::Window::WindowOrientation orientation );
+
+  /**
+   * @copydoc Dali::Window::SetClass()
+   */
+  void SetClass( std::string name, std::string klass );
+
+  /**
+   * @copydoc Dali::Window::Raise()
+   */
+  void Raise();
+
+  /**
+   * @copydoc Dali::Window::Lower()
+   */
+  void Lower();
+
+  /**
+   * @copydoc Dali::Window::Activate()
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::Window::AddAvailableOrientation()
+   */
+  void AddAvailableOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::RemoveAvailableOrientation()
+   */
+  void RemoveAvailableOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::SetAvailableOrientations()
+   */
+  void SetAvailableOrientations(const std::vector<Dali::Window::WindowOrientation>& orientations);
+
+  /**
+   * @copydoc Dali::Window::GetAvailableOrientations()
+   */
+  const std::vector<Dali::Window::WindowOrientation>& GetAvailableOrientations();
+
+  /**
+   * @copydoc Dali::Window::SetPreferredOrientation()
+   */
+  void SetPreferredOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::GetPreferredOrientation()
+   */
+  Dali::Window::WindowOrientation GetPreferredOrientation();
+
+  /**
+   * @copydoc Dali::Window::GetDragAndDropDetector() const
+   */
+  Dali::DragAndDropDetector GetDragAndDropDetector() const;
+
+  /**
+   * @copydoc Dali::Window::GetNativeHandle() const
+   */
+  Dali::Any GetNativeHandle() const;
+
+  /**
+   * Called from Orientation after the Change signal has been sent
+   */
+  void RotationDone( int orientation, int width, int height );
+
+private:
+  /**
+   * Private constructor.
+   * @sa Window::New()
+   */
+  Window();
+
+  /**
+   * Destructor
+   */
+  virtual ~Window();
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize(const PositionSize& posSize, const std::string& name, const std::string& className);
+
+  /**
+   * Shows / hides the indicator bar.
+   * Handles close/open if rotation changes whilst hidden
+   */
+  void DoShowIndicator( Dali::Window::WindowOrientation lastOrientation );
+
+  /**
+   * Close current indicator and open a connection onto the new indicator service.
+   * Effect may not be synchronous if waiting for an indicator update on existing connection.
+   */
+  void DoRotateIndicator( Dali::Window::WindowOrientation orientation );
+
+  /**
+   * Change the indicator actor's rotation to match the current orientation
+   */
+  void SetIndicatorActorRotation();
+
+  /**
+   * Set the indicator properties on the window
+   */
+  void SetIndicatorProperties( bool isShown, Dali::Window::WindowOrientation lastOrientation );
+
+private: // Indicator::Observer interface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Indicator::Observer::IndicatorTypeChanged()
+   */
+  virtual void IndicatorTypeChanged( Indicator::Type type );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Indicator::Observer::IndicatorClosed()
+   */
+  virtual void IndicatorClosed(Indicator* indicator);
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Indicator::Observer::IndicatorVisibilityChanged()
+   */
+  virtual void IndicatorVisibilityChanged( bool isVisible );
+
+private: // Adaptor::Observer interface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Adaptor::Observer::OnStart()
+   */
+  virtual void OnStart();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Adaptor::Observer::OnPause()
+   */
+  virtual void OnPause();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Adaptor::Observer::OnResume()
+   */
+  virtual void OnResume();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Adaptor::Observer::OnStop()
+   */
+  virtual void OnStop();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::Adaptor::Observer::OnDestroy()
+   */
+  virtual void OnDestroy();
+
+public: // Signals
+
+  /**
+   * The user should connect to this signal to get a timing when indicator was shown / hidden.
+   */
+  IndicatorSignalType& IndicatorVisibilityChangedSignal() { return mIndicatorVisibilityChangedSignal; }
+
+  /**
+   * This signal is emitted when the window is requesting to be deleted
+   */
+  SignalType& DeleteRequestSignal() { return mDeleteRequestSignal; }
+
+private:
+
+  typedef std::vector<Indicator*> DiscardedIndicators;
+
+  RenderSurface*                   mSurface;
+  Dali::Window::IndicatorVisibleMode mIndicatorVisible; ///< public state
+  bool                             mIndicatorIsShown:1; ///< private state
+  bool                             mShowRotatedIndicatorOnClose:1;
+  bool                             mStarted:1;
+  bool                             mIsTransparent:1;
+  bool                             mWMRotationAppSet:1;
+  bool                             mEcoreEventHander:1;
+  Indicator*                       mIndicator;
+  Dali::Window::WindowOrientation  mIndicatorOrientation;
+  Dali::Window::WindowOrientation  mNextIndicatorOrientation;
+  Dali::Window::IndicatorBgOpacity mIndicatorOpacityMode;
+  Integration::SystemOverlay*      mOverlay;
+  Adaptor*                         mAdaptor;
+  Dali::DragAndDropDetector        mDragAndDropDetector;
+
+  struct EventHandler;
+  EventHandler*                    mEventHandler;
+
+  OrientationPtr                               mOrientation;
+  std::vector<Dali::Window::WindowOrientation> mAvailableOrientations;
+  Dali::Window::WindowOrientation              mPreferredOrientation;
+
+  // Signals
+  IndicatorSignalType mIndicatorVisibilityChangedSignal;
+  SignalType          mDeleteRequestSignal;
+};
+
+} // namespace Adaptor
+} // namepsace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::Window& GetImplementation(Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  BaseObject& object = window.GetBaseObject();
+  return static_cast<Internal::Adaptor::Window&>(object);
+}
+
+inline const Internal::Adaptor::Window& GetImplementation(const Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  const BaseObject& object = window.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Window&>(object);
+}
+
+} // namespace Dali
+
+
+#endif // __DALI_INTERNAL_WINDOW_H__
diff --git a/adaptors/common/window-visibility-observer.h b/adaptors/common/window-visibility-observer.h
new file mode 100644 (file)
index 0000000..0c8a9c8
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef __DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H__
+#define __DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * An interface used to observe when the application's window is shown/hidden.
+ */
+class WindowVisibilityObserver
+{
+public:
+
+  /**
+   * Called when the window becomes fully or partially visible.
+   */
+  virtual void OnWindowShown() = 0;
+
+  /**
+   * Called when the window is fully hidden.
+   */
+  virtual void OnWindowHidden() = 0;
+
+protected:
+
+  /**
+   * Protected Constructor.
+   */
+  WindowVisibilityObserver()
+  {
+  }
+
+  /**
+   * Protected virtual destructor.
+   */
+  virtual ~WindowVisibilityObserver()
+  {
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H__
diff --git a/adaptors/devel-api/adaptor-framework/accessibility-action-handler.h b/adaptors/devel-api/adaptor-framework/accessibility-action-handler.h
new file mode 100644 (file)
index 0000000..9cac7ca
--- /dev/null
@@ -0,0 +1,218 @@
+#ifndef __DALI_ACCESSIBILITY_ACTION_HANDLER_H__
+#define __DALI_ACCESSIBILITY_ACTION_HANDLER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/events/touch-event.h>
+
+namespace Dali
+{
+
+/**
+ * AccessibilityActionHandler is an abstract interface, used by Dali to handle accessibility actions
+ * passed by the accessibility manager.
+ */
+class AccessibilityActionHandler
+{
+public:
+
+  /**
+   * Change the accessibility status when Accessibility feature(screen-reader) turned on or off.
+   * @return whether the status is changed or not.
+   */
+  virtual bool ChangeAccessibilityStatus() = 0;
+
+  /**
+   * Clear the accessibility focus from the current focused actor.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool ClearAccessibilityFocus() = 0;
+
+  /**
+   * Perform the accessibility action associated with a scroll event.
+   * @param touchEvent The touch point (and time) of the event.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool AccessibilityActionScroll( Dali::TouchEvent& touchEvent ) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick up).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPrevious(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick down).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionNext(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick left).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPrevious(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick right).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadNext(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to focus and read the actor (by one finger tap or move).
+   * @param allowReadAgain true if the action read again the same object (i.e. read action)
+   *                       false if the action just read when the focus object is changed (i.e. over action)
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionRead(bool allowReadAgain) = 0;
+
+  /**
+   * Perform the accessibility action to activate the current focused actor (by one finger double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionActivate() = 0;
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move up and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionUp() = 0;
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move down and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionDown() = 0;
+
+  /**
+   * Perform the accessibility action to navigate back (by two fingers circle draw).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionBack() = 0;
+
+  /**
+   * Perform the accessibility action to scroll up the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollUp() = 0;
+
+  /**
+   * Perform the accessibility action to scroll down the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollDown() = 0;
+
+  /**
+   * Perform the accessibility action to scroll left to the previous page (by two finger swipe left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageLeft() = 0;
+
+  /**
+   * Perform the accessibility action to scroll right to the next page (by two finger swipe right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageRight() = 0;
+
+  /**
+   * Perform the accessibility action to scroll up to the previous page (by one finger swipe left and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageUp() = 0;
+
+  /**
+   * Perform the accessibility action to scroll down to the next page (by one finger swipe right and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageDown() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the screen
+   * (by one finger swipe up and down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToFirst() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the last item on the screen
+   * (by one finger swipe down and up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToLast() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the top
+   * and read from the top item continously (by three fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromTop() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to and read from the next item
+   * continously (by three fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromNext() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to do the zooming (by one finger triple tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionZoom() = 0;
+
+  /**
+   * Perform the accessibility action to read the information in the indicator (by two fingers triple tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadIndicatorInformation() = 0;
+
+  /**
+   * Perform the accessibility action to pause/resume the current read out (by two fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPauseResume() = 0;
+
+  /**
+   * Perform the accessibility action to start/stop the current action (by two fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionStartStop() = 0;
+
+  /**
+   * Perform the accessibility action to mouse move (by one finger tap & hold and move).
+   * @param touchEvent touch event structure
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionTouch(const Dali::TouchEvent& touchEvent) = 0;
+
+}; // class AccessibilityActionHandler
+
+} // namespace Dali
+
+#endif // __DALI_ACCESSIBILITY_ACTION_HANDLER_H__
diff --git a/adaptors/devel-api/adaptor-framework/accessibility-adaptor.cpp b/adaptors/devel-api/adaptor-framework/accessibility-adaptor.cpp
new file mode 100644 (file)
index 0000000..8cf99a5
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <accessibility-adaptor.h>
+
+// INTERNAL INCLUDES
+#include <accessibility-adaptor-impl.h>
+
+namespace Dali
+{
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+{
+}
+
+AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::Get();
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).GetReadPosition();
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).IsEnabled();
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetActionHandler(handler);
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetGestureHandler(handler);
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionActivateEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y,  bool allowReadAgain)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadEvent(x, y, allowReadAgain);
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionClearFocusEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionTouchEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionBackEvent();
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionEnableEvent();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDisableEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageLeftEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageRightEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToFirstEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToLastEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromTopEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromNextEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionZoomEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadIndicatorInformationEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPauseResumeEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionStartStopEvent();
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& manager )
+: BaseHandle( &manager )
+{
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* manager )
+: BaseHandle( manager )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/accessibility-adaptor.h b/adaptors/devel-api/adaptor-framework/accessibility-adaptor.h
new file mode 100644 (file)
index 0000000..0fb3d7e
--- /dev/null
@@ -0,0 +1,348 @@
+#ifndef __DALI_ACCESSIBILITY_ADAPTOR_H__
+#define __DALI_ACCESSIBILITY_ADAPTOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class AccessibilityAdaptor;
+}
+}
+
+class AccessibilityActionHandler;
+class AccessibilityGestureHandler;
+class TouchPoint;
+
+/**
+ * @brief The AccessibilityAdaptor provides communication to the indicator and the accessibility manager interface (implemented in toolkit).
+ *
+ */
+class DALI_IMPORT_API AccessibilityAdaptor : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling getting the adaptor from Dali::Adaptor.
+   */
+  AccessibilityAdaptor();
+
+  /**
+   * @brief Retrieve a handle to the AccessibilityAdaptor.
+   *
+   * @return A handle to the AccessibilityAdaptor.
+   */
+  static AccessibilityAdaptor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AccessibilityAdaptor();
+
+  /**
+   * @brief Returns the current position of the read action.
+   * @return The current event position.
+   */
+  Vector2 GetReadPosition() const;
+
+  /**
+   * @brief Query whether the accessibility(screen-reader) is enabled.
+   *
+   * The accessibility will be enabled by system setting.
+   * @return True if the accessibility(screen-reader) is enabled.
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @brief Set the handler to handle accessibility actions.
+   *
+   * @param[in] handler The Accessibility action handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetActionHandler(AccessibilityActionHandler& handler);
+
+  /**
+   * @brief Set the handler to handle accessibility gestures.
+   *
+   * @param[in] handler The Accessibility gesture handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the next focusable actor
+   * (by one finger flick down).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the previous focusable actor
+   * (by one finger flick up).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to activate the current focused actor (by one
+   * finger )
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionActivateEvent();
+
+  /**
+   * @brief Handle the accessibility action to focus and read the actor (by one finger tap or move).
+   *
+   * @param x x position of event
+   * @param y y position of event
+   * @param allowReadAgain true if the action read again the same object (i.e. read action)
+   *                       false if the action just read when the focus object is changed (i.e. over action)
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the next focusable actor
+   * (by one finger flick right).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the previous focusable actor
+   * (by one finger flick up).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the front
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to change the value when the current focused
+   * actor is a slider (by double finger down and move up and right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to change the value when the current focused
+   * actor is a slider (by double finger down and move down and left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to clear the focus from the current focused
+   * actor if any, so that no actor is focused in the focus chain.
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionClearFocusEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll when there is a scroller on the touched position
+   * (by 2 finger touch & move, 2 finger flick).
+   *
+   * @param[in]  point      The touch point information.
+   * @param[in]  timeStamp  The time the touch occurred.
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @brief Handle the accessibility action to move for the current focused actor
+   * (by 1 finger tap & hold and move).
+   *
+   * @param[in]  point      The touch point information.
+   * @param[in]  timeStamp  The time the touch occurred.
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @brief Handle the accessibility action to navigate back (by two fingers circle draw).
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionBackEvent();
+
+  /**
+   * @brief Handle the accessibility action to enable the feature.
+   */
+  void HandleActionEnableEvent();
+
+  /**
+   * @brief Handle the accessibility action to disable the feature.
+   */
+  void HandleActionDisableEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll up the list and focus on
+   * the first item on the list after the scrolling and read the item
+   * (by two finger swipe up).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll down the list and focus on
+   * the first item on the list after the scrolling and read the item
+   * (by two finger swipe down).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll left to the previous page
+   * (by two finger swipe left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageLeftEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll right to the next page
+   * (by two finger swipe right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageRightEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll up to the previous page
+   * (by one finger swipe left and right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll down to the next page
+   * (by one finger swipe right and left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the first item on the screen
+   * (by one finger swipe up and down).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionMoveToFirstEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the last item on the screen
+   * (by one finger swipe down and up).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionMoveToLastEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the first item on the top
+   * and read from the top item continously (by three fingers single tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadFromTopEvent();
+
+  /**
+   * @brief Handle the accessibility action to move focus to and read from the next focusable
+   * actor continously (by three fingers double tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadFromNextEvent();
+
+  /**
+   * @brief Handle the accessibility action to do the zooming
+   * (by one finger triple tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionZoomEvent();
+
+  /**
+   * @brief Handle the accessibility action to read the information in the indicator
+   * (by two fingers triple tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadIndicatorInformationEvent();
+
+  /**
+   * @brief Handle the accessibility action to pause/resume the current speech
+   * (by two fingers single tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadPauseResumeEvent();
+
+  /**
+   * @brief Handle the accessibility action to start/stop the current action
+   * (by two fingers double tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionStartStopEvent();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Adaptor::Internal implementation.
+   *
+   * @param[in] adaptor The AccessibilityAdaptor implementation.
+   */
+  DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& adaptor );
+
+  /**
+   * @brief This constructor is used by AccessibilityAdaptor::Get().
+   *
+   * @param[in] adaptor A pointer to the accessibility adaptor.
+   */
+  explicit DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* adaptor );
+};
+
+} // namespace Dali
+
+#endif // __DALI_ACCESSIBILITY_ADAPTOR_H__
diff --git a/adaptors/devel-api/adaptor-framework/accessibility-gesture-handler.h b/adaptors/devel-api/adaptor-framework/accessibility-gesture-handler.h
new file mode 100644 (file)
index 0000000..b525c47
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __DALI_ACCESSIBILITY_GESTURE_HANDLER_H__
+#define __DALI_ACCESSIBILITY_GESTURE_HANDLER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/events/pan-gesture-event.h>
+
+namespace Dali
+{
+
+/**
+ * AccessibilityGestureHandler is an interface used by Dali to handle accessibility gestures
+ * passed by the accessibility manager.
+ */
+class AccessibilityGestureHandler
+{
+public:
+
+  /**
+   * Handle the accessibility pan gesture.
+   * @param[in]  panEvent  The pan event to be handled.
+   * @return whether the gesture is handled successfully or not.
+   */
+  virtual bool HandlePanGesture( const Integration::PanGestureEvent& panEvent ) = 0;
+
+}; // class AccessibilityGestureHandler
+
+} // namespace Dali
+
+#endif // __DALI_ACCESSIBILITY_GESTURE_HANDLER_H__
diff --git a/adaptors/devel-api/adaptor-framework/bitmap-loader.cpp b/adaptors/devel-api/adaptor-framework/bitmap-loader.cpp
new file mode 100644 (file)
index 0000000..142e600
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "bitmap-loader.h"
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/resource-types.h>
+#include <dali/integration-api/resource-cache.h>
+
+// INTERNAL INCLUDES
+#include "image-loaders/image-loader.h"
+#include <bitmap-loader-impl.h>
+
+namespace Dali
+{
+
+BitmapLoader BitmapLoader::New(const std::string& filename)
+{
+  IntrusivePtr<Internal::BitmapLoader> internal = Internal::BitmapLoader::New(filename);
+  return BitmapLoader( internal.Get() );
+}
+
+BitmapLoader::BitmapLoader()
+{
+}
+
+BitmapLoader::BitmapLoader(Internal::BitmapLoader* internal)
+: BaseHandle( internal )
+{
+}
+
+BitmapLoader::~BitmapLoader()
+{
+}
+
+BitmapLoader::BitmapLoader( const BitmapLoader& handle )
+: BaseHandle( handle )
+{
+}
+
+BitmapLoader& BitmapLoader::operator=(const BitmapLoader& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+unsigned char* BitmapLoader::GetPixelData() const
+{
+  return GetImplementation(*this).GetPixelData();
+}
+
+unsigned int BitmapLoader::GetImageHeight() const
+{
+  return GetImplementation(*this).GetImageHeight();
+}
+
+unsigned int BitmapLoader::GetImageWidth() const
+{
+  return GetImplementation(*this).GetImageWidth();
+}
+
+unsigned int BitmapLoader::GetBufferStride() const
+{
+  return GetImplementation(*this).GetBufferStride();
+}
+
+Pixel::Format BitmapLoader::GetPixelFormat() const
+{
+  return GetImplementation(*this).GetPixelFormat();
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/bitmap-loader.h b/adaptors/devel-api/adaptor-framework/bitmap-loader.h
new file mode 100644 (file)
index 0000000..12971bd
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef __DALI_BITMAP_LOADER_H__
+#define __DALI_BITMAP_LOADER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+namespace Internal
+{
+class BitmapLoader;
+}
+
+class DALI_IMPORT_API BitmapLoader : public BaseHandle
+{
+public:
+  /**
+   * @brief Create an initialized bitmap loader. This will automatically load the image.
+   *
+   * @param[in] filename  Filename of the bitmap image to load.
+   */
+  static BitmapLoader New(const std::string& filename);
+
+  /**
+   * @brief Create an empty handle.
+   *
+   * Use BitmapLoader::New() to create an initialized object.
+   */
+  BitmapLoader();
+
+  /**
+   * Destructor
+   */
+  ~BitmapLoader();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  BitmapLoader(const BitmapLoader& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  BitmapLoader& operator=(const BitmapLoader& rhs);
+
+public:
+
+  /**
+   * Get the raw pixel data.
+   * @return The pixel data. Use the GetHeight(), GetWidth(), GetStride() and GetPixelFormat() methods
+   * to decode the data.
+   */
+  unsigned char* GetPixelData() const;
+
+  /**
+   * Get the buffer height in pixels
+   * @return the height of the buffer in pixels
+   */
+  unsigned int GetImageHeight() const;
+
+  /**
+   * Get the buffer width in pixels
+   * @return the width of the buffer in pixels
+   */
+  unsigned int GetImageWidth() const;
+
+  /**
+   * Get the number of bytes in each row of pixels
+   * @return The buffer stride in bytes.
+   */
+  unsigned int GetBufferStride() const;
+
+  /**
+   * Get the pixel format of the loaded bitmap.
+   */
+  Pixel::Format GetPixelFormat() const;
+
+public: // Not intended for application developers
+
+  explicit DALI_INTERNAL BitmapLoader(Internal::BitmapLoader*);
+};
+
+} // Dali
+
+#endif // __DALI_BITMAP_LOADER_H__
diff --git a/adaptors/devel-api/adaptor-framework/bitmap-saver.cpp b/adaptors/devel-api/adaptor-framework/bitmap-saver.cpp
new file mode 100644 (file)
index 0000000..4340e6d
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "bitmap-saver.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <platform-abstractions/tizen/resource-loader/resource-loader.h>
+#include <platform-abstractions/tizen/image-loaders/loader-jpeg.h>
+#include <platform-abstractions/tizen/image-loaders/loader-png.h>
+#include <image-encoder.h>
+
+namespace Dali
+{
+
+// Pieces needed to save compressed images (temporary location while plumbing):
+namespace
+{
+
+/**
+ * Simple function to tell intended image file format from filename
+ */
+FileFormat GetFormatFromFileName( const std::string& filename )
+{
+  if (filename.length() < 5)
+  {
+    DALI_LOG_WARNING("Invalid (short) filename.");
+  }
+  FileFormat format(INVALID_FORMAT);
+
+  const std::size_t filenameSize = filename.length();
+
+  if(filenameSize >= 4){ // Avoid throwing out_of_range or failing silently if exceptions are turned-off on the compare(). (http://www.cplusplus.com/reference/string/string/compare/)
+    if( !filename.compare( filenameSize - 4, 4, ".jpg" )
+        || !filename.compare( filenameSize - 4, 4, ".JPG" ) )
+    {
+      format = JPG_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".png" )
+             || !filename.compare( filenameSize - 4, 4, ".PNG" ) )
+    {
+      format = PNG_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".bmp" )
+             || !filename.compare( filenameSize - 4, 4, ".BMP" ) )
+    {
+      format = BMP_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".gif" )
+             || !filename.compare( filenameSize - 4, 4, ".GIF" ) )
+    {
+      format = GIF_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".ico" )
+             || !filename.compare( filenameSize - 4, 4, ".ICO" ) )
+    {
+      format = ICO_FORMAT;
+    }
+    else if(filenameSize >= 5){
+      if( !filename.compare( filenameSize - 5, 5, ".jpeg" )
+          || !filename.compare( filenameSize - 5, 5, ".JPEG" ) )
+      {
+        format = JPG_FORMAT;
+      }
+    }
+  }
+
+  return format;
+}
+
+bool EncodeToFormat( const unsigned char* pixelBuffer,
+                     std::vector< unsigned char >& encodedPixels,
+                     FileFormat formatEncoding,
+                     std::size_t width,
+                     std::size_t height,
+                     Pixel::Format pixelFormat )
+{
+  switch( formatEncoding )
+  {
+    case JPG_FORMAT:
+    {
+      return TizenPlatform::EncodeToJpeg( pixelBuffer, encodedPixels, width, height, pixelFormat );
+      break;
+    }
+    case PNG_FORMAT:
+    {
+      return TizenPlatform::EncodeToPng( pixelBuffer, encodedPixels, width, height, pixelFormat );
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Format not supported for image encoding (supported formats are PNG and JPEG)");
+      break;
+    }
+  }
+  return false;
+}
+} // anonymous namespace
+
+
+bool EncodeToFile(const unsigned char* const pixelBuffer,
+                  const std::string& filename,
+                  const Pixel::Format pixelFormat,
+                  const std::size_t width,
+                  const std::size_t height )
+{
+  DALI_ASSERT_DEBUG(pixelBuffer != 0 && filename.size() > 4 && width > 0 && height > 0);
+  std::vector< unsigned char > pixbufEncoded;
+  const FileFormat format = GetFormatFromFileName( filename );
+  const bool encodeResult = EncodeToFormat( pixelBuffer, pixbufEncoded, format, width, height, pixelFormat );
+  if(!encodeResult)
+  {
+    DALI_LOG_ERROR("Encoding pixels failed");
+    return false;
+  }
+  return TizenPlatform::ResourceLoader::SaveFile( filename, pixbufEncoded );
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/bitmap-saver.h b/adaptors/devel-api/adaptor-framework/bitmap-saver.h
new file mode 100644 (file)
index 0000000..b8e67be
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __DALI_ADAPTOR_BITMAP_SAVER_H__
+#define __DALI_ADAPTOR_BITMAP_SAVER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/images/pixel.h>
+
+namespace Dali
+{
+
+/**
+ * Store the given pixel data to a file.
+ * The suffix of the filename determines what type of file will be stored,
+ * currently only jpeg and png formats are supported.
+ *
+ * @param[in] pixelBuffer Pointer to the pixel data
+ * @param[in] filename    Filename to save
+ * @param[in] pixelFormat The format of the buffer's pixels
+ * @param[in] width       The width of the image in pixels
+ * @param[in] height      The height of the image in pixels
+ *
+ * @return true if the file was saved
+ */
+DALI_IMPORT_API bool EncodeToFile(const unsigned char* const pixelBuffer,
+                                  const std::string& filename,
+                                  const Pixel::Format pixelFormat,
+                                  const std::size_t width,
+                                  const std::size_t height);
+
+} // namespace Dali
+
+
+#endif // __DALI_ADAPTOR_BITMAP_SAVER_H__
diff --git a/adaptors/devel-api/adaptor-framework/clipboard-event-notifier.cpp b/adaptors/devel-api/adaptor-framework/clipboard-event-notifier.cpp
new file mode 100644 (file)
index 0000000..7616580
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <clipboard-event-notifier.h>
+
+// INTERNAL INCLUDES
+#include <clipboard-event-notifier-impl.h>
+
+namespace Dali
+{
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+{
+}
+
+ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::Get();
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).GetContent();
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).SetContent(content);
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ClearContent();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).EmitContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventSignalType& ClipboardEventNotifier::ContentSelectedSignal()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier )
+: BaseHandle( notifier )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/clipboard-event-notifier.h b/adaptors/devel-api/adaptor-framework/clipboard-event-notifier.h
new file mode 100644 (file)
index 0000000..fd5cfc4
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef __DALI_CLIPBOARD_EVENT_NOTIFIER_H__
+#define __DALI_CLIPBOARD_EVENT_NOTIFIER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class ClipboardEventNotifier;
+}
+}
+
+/**
+ * @brief The ClipboardEventNotifier provides signals when clipboard events are received from the device.
+ */
+class DALI_IMPORT_API ClipboardEventNotifier : public BaseHandle
+{
+public:
+
+  // Typedefs
+
+  /**
+   * @brief Clipboard event
+   */
+  typedef Signal< void ( ClipboardEventNotifier& ) > ClipboardEventSignalType;
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by getting the notifier from Dali::Adaptor.
+   */
+  ClipboardEventNotifier();
+
+  /**
+   * @brief Retrieve a handle to the ClipboardEventNotifier instance.
+   *
+   * @return A handle to the ClipboardEventNotifier
+   */
+  static ClipboardEventNotifier Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ClipboardEventNotifier();
+
+  /**
+   * @brief Returns the selected content.
+   * @return A reference to the string representing the selected content.
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @brief Sets the selected content.
+   * @param[in] content  A string that represents the content that has been selected.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * @brief Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * @brief Called when content is selected in the clipboard.
+   */
+  void EmitContentSelectedSignal();
+
+public:  // Signals
+
+  /**
+   * @brief This is emitted when content is selected from the clipboard.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( ClipboardEventNotifier& notifier );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  ClipboardEventSignalType& ContentSelectedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by ClipboardEventNotifier::Get().
+   *
+   * @param[in] notifier A pointer to the drag and drop notifier.
+   */
+  explicit DALI_INTERNAL ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier );
+};
+
+} // namespace Dali
+
+#endif // __DALI_CLIPBOARD_EVENT_NOTIFIER_H__
diff --git a/adaptors/devel-api/adaptor-framework/clipboard.cpp b/adaptors/devel-api/adaptor-framework/clipboard.cpp
new file mode 100644 (file)
index 0000000..95f1b52
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <clipboard.h>
+
+// INTERNAL INCLUDES
+#include <clipboard-impl.h>
+
+namespace Dali
+{
+
+Clipboard::Clipboard()
+{
+}
+Clipboard::~Clipboard()
+{
+}
+Clipboard::Clipboard(Internal::Adaptor::Clipboard *impl)
+  : BaseHandle(impl)
+{
+}
+
+Clipboard Clipboard::Get()
+{
+  return Internal::Adaptor::Clipboard::Get();
+}
+bool Clipboard::SetItem( const std::string &itemData)
+{
+  return GetImplementation(*this).SetItem( itemData );
+}
+
+std::string Clipboard::GetItem( unsigned int index )
+{
+  return GetImplementation(*this).GetItem( index );
+}
+
+unsigned int Clipboard::NumberOfItems()
+{
+  return GetImplementation(*this).NumberOfItems();
+}
+
+void Clipboard::ShowClipboard()
+{
+  GetImplementation(*this).ShowClipboard();
+}
+
+void Clipboard::HideClipboard()
+{
+  GetImplementation(*this).HideClipboard();
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/clipboard.h b/adaptors/devel-api/adaptor-framework/clipboard.h
new file mode 100644 (file)
index 0000000..9b5a54a
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef  __DALI_CLIPBOARD_H__
+#define  __DALI_CLIPBOARD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/base-handle.h>
+
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+class Clipboard;
+}
+}
+
+/**
+ * @brief Interface to the device's clipboard.
+ *
+ * Clipboard can manage it's item and set show / hide status.
+ */
+
+class DALI_IMPORT_API Clipboard : public BaseHandle
+{
+public:
+  /**
+   * @brief Create an uninitialized Clipboard.
+   *
+   * this can be initialized with one of the derived Clipboard' New() methods
+   */
+  Clipboard();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Clipboard();
+
+  /**
+   * @brief This constructor is used by Adaptor::GetClipboard().
+   *
+   * @param[in] clipboard A pointer to the clipboard.
+   */
+  explicit DALI_INTERNAL Clipboard( Internal::Adaptor::Clipboard* clipboard );
+
+  /**
+   * @brief Retrieve a handle to the ClipboardEventNotifier instance.
+   *
+   * @return A handle to the Clipboard
+   */
+  static Clipboard Get();
+
+  /**
+   * @brief Send the given string to the clipboard.
+   *
+   * @param[in] itemData string to send to clip board
+   * @return bool true if the internal clip board sending was successful.
+   */
+  bool SetItem( const std::string& itemData );
+
+  /**
+   * @brief Retreive the string at the given index in the clipboard.
+   *
+   * @param[in] index item in clipboard list to retrieve
+   * @return string the text item at the current index.
+   */
+  std::string GetItem( unsigned int index );
+
+  /**
+   * @brief Returns the number of item currently in the clipboard.
+   *
+   * @return unsigned int number of clipboard items
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @brief Show the clipboard window.
+   */
+  void ShowClipboard();
+
+  /**
+   * @brief Hide the clipboard window.
+   */
+  void HideClipboard();
+
+};
+} // namespace Dali
+
+#endif // __DALI_CLIPBOARD_H__
diff --git a/adaptors/devel-api/adaptor-framework/color-controller.cpp b/adaptors/devel-api/adaptor-framework/color-controller.cpp
new file mode 100644 (file)
index 0000000..3a134b1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <color-controller.h>
+
+// INTERNAL INCLUDES
+#include <color-controller-impl.h>
+
+namespace Dali
+{
+
+ColorController::ColorController()
+{
+}
+
+ColorController::ColorController(const ColorController& controller)
+: BaseHandle(controller)
+{
+}
+
+ColorController& ColorController::operator=(const ColorController& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+ColorController ColorController::Get()
+{
+  return Internal::Adaptor::ColorController::Get();
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return GetImplementation(*this).RetrieveColor( colorCode, colorValue );
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  return GetImplementation(*this).RetrieveColor( colorCode, textColor, textOutlineColor, textShadowColor );
+}
+
+ColorController::ColorController(Internal::Adaptor::ColorController* internal)
+: BaseHandle(internal)
+{
+}
+
+}
diff --git a/adaptors/devel-api/adaptor-framework/color-controller.h b/adaptors/devel-api/adaptor-framework/color-controller.h
new file mode 100644 (file)
index 0000000..8508880
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef __DALI_COLOR_CONTROLLER_H__
+#define __DALI_COLOR_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/math/vector4.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class ColorController;
+}
+}
+
+/**
+ * Color controller currently caches the changeable color table which updates with the theme change
+ *
+ * It provides the functionality of retrieving a RGBA color by passing in the color code string.
+ */
+class DALI_IMPORT_API ColorController : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized ColorController handle.
+   */
+  ColorController();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  colorController  The Color Controller to copy from.
+   */
+  ColorController( const ColorController& colorController);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  ColorController& operator=(const ColorController& rhs);
+
+  /**
+   * @brief Retrieve the initialized instance of the ColorController.
+   *
+   * @return Handle to ColorController.
+   */
+  static ColorController Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ColorController();
+
+  /**
+   * @brief Retrieve the RGB value by given the color code.
+   *
+   * @param[in] colorCode The color code string.
+   * @param[out] colorValue The RGBA color
+   * @return true if the color code exists, otherwise false
+   */
+  bool RetrieveColor( const std::string& colorCode, Vector4& colorValue );
+
+  /**
+    * @brief Retrieve the RGB values by given the color code.
+    *
+    * @param[in] colorCode The color code string.
+    * @param[out] textColor The text color.
+    * @param[out] textOutlineColor The text outline color.
+    * @param[out] textShadowColor The text shadow color.
+    * @return true if the color code exists, otherwise false
+    */
+  bool RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor);
+
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] colorController A pointer the internal color controller.
+   */
+  explicit DALI_INTERNAL ColorController(Internal::Adaptor::ColorController* colorController);
+};
+
+
+} //namespace Dali
+
+#endif /* __DALI_COLOR_CONTROLLER_H__ */
diff --git a/adaptors/devel-api/adaptor-framework/drag-and-drop-detector.cpp b/adaptors/devel-api/adaptor-framework/drag-and-drop-detector.cpp
new file mode 100644 (file)
index 0000000..29fa570
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <drag-and-drop-detector.h>
+
+// INTERNAL INCLUDES
+#include <drag-and-drop-detector-impl.h>
+
+namespace Dali
+{
+
+DragAndDropDetector::DragAndDropDetector()
+{
+}
+
+DragAndDropDetector::~DragAndDropDetector()
+{
+}
+
+const std::string& DragAndDropDetector::GetContent() const
+{
+  return GetImplementation(*this).GetContent();
+}
+
+Vector2 DragAndDropDetector::GetCurrentScreenPosition() const
+{
+  return GetImplementation(*this).GetCurrentScreenPosition();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::EnteredSignal()
+{
+  return GetImplementation(*this).EnteredSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::ExitedSignal()
+{
+  return GetImplementation(*this).ExitedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::MovedSignal()
+{
+  return GetImplementation(*this).MovedSignal();
+}
+
+DragAndDropDetector::DragAndDropSignal& DragAndDropDetector::DroppedSignal()
+{
+  return GetImplementation(*this).DroppedSignal();
+}
+
+DragAndDropDetector::DragAndDropDetector( Internal::Adaptor::DragAndDropDetector* detector )
+: BaseHandle( detector )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/drag-and-drop-detector.h b/adaptors/devel-api/adaptor-framework/drag-and-drop-detector.h
new file mode 100644 (file)
index 0000000..46b8517
--- /dev/null
@@ -0,0 +1,183 @@
+#ifndef __DALI_DRAG_AND_DROP_DETECTOR_H__
+#define __DALI_DRAG_AND_DROP_DETECTOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class DragAndDropDetector;
+}
+}
+
+/**
+ * @brief The DragAndDropDetector%s provides signals when draggable objects are dragged into our window.
+ *
+ * It provides signals for when the draggable object enters our window, moves around in our window,
+ * leaves our window and when it is finally dropped into our window.
+ *
+ * The basic usage is shown below:
+ *
+ * @code
+ *
+ *  void Example()
+ *  {
+ *    DragAndDropDetector detector( window::GetDragAndDropDetector() );
+ *
+ *    // Get notifications when the draggable item enters our window
+ *    detector.EnteredSignal().Connect( &OnEntered );
+ *
+ *    // Get notifications when the draggable item leaves our window
+ *    detector.ExitedSignal().Connect( &OnExited );
+ *
+ *    // Get notifications when the draggable item is moved within our window
+ *    detector.MovedSignal().Connect( &OnMoved );
+ *
+ *    // Get notifications when the draggable item is dropped
+ *    detector.DroppedSignal().Connect( &OnDropped );
+ *  }
+ *
+ *  void OnEntered( DragAndDropDetector detector )
+ *  {
+ *    // Change mode as required
+ *  }
+ *
+ *  void OnExited( DragAndDropDetector detector )
+ *  {
+ *    // Change mode as required
+ *  }
+ *
+ *  void OnMoved( DragAndDropDetector detector )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Position = " << detector.GetCurrentScreenPosition() << std::endl;
+ *  }
+ *
+ *  void OnDropped( DragAndDropDetector detector )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Position = " << detector.GetCurrentScreenPosition() << ", Content = " << detector.GetContent() << std::endl;
+ *  }
+ *
+ * @endcode
+ */
+class DALI_IMPORT_API DragAndDropDetector : public BaseHandle
+{
+public:
+
+  // Typedefs
+
+  typedef Signal< void ( DragAndDropDetector ) > DragAndDropSignal; ///< Drag & Drop signal
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling getting the detector from Dali::Window.
+   */
+  DragAndDropDetector();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~DragAndDropDetector();
+
+  /**
+   * @brief Returns the dropped content.
+   *
+   * @return A reference to the string representing the dropped content.
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @brief Returns the current position of the dragged object.
+   *
+   * This is the dropped position when an object is dropped.
+   * @return The current screen position.
+   */
+  Vector2 GetCurrentScreenPosition() const;
+
+  // Signals
+
+  /**
+   * @brief This is emitted when a dragged object enters a DALi window.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& EnteredSignal();
+
+  /**
+   * @brief This is emitted when a dragged object leaves a DALi window.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& ExitedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object is moved within the DALi window.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& MovedSignal();
+
+  /**
+   * @brief This is emitted when a dragged object is dropped within a DALi window.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( DragAndDropDetector detector );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  DragAndDropSignal& DroppedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by DragAndDropDetector::Get().
+   *
+   * @param[in] detector A pointer to the drag and drop detector.
+   */
+  explicit DALI_INTERNAL DragAndDropDetector( Internal::Adaptor::DragAndDropDetector* detector );
+};
+
+} // namespace Dali
+
+#endif // __DALI_DRAG_AND_DROP_DETECTOR_H__
diff --git a/adaptors/devel-api/adaptor-framework/event-feeder.cpp b/adaptors/devel-api/adaptor-framework/event-feeder.cpp
new file mode 100644 (file)
index 0000000..7ddf711
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <event-feeder.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace EventFeeder
+{
+
+void FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedTouchPoint( point, timeStamp );
+  }
+}
+
+void FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedWheelEvent( wheelEvent );
+  }
+}
+
+void FeedKeyEvent( KeyEvent& keyEvent )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedKeyEvent( keyEvent );
+  }
+}
+
+} // namespace EventFeeder
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/event-feeder.h b/adaptors/devel-api/adaptor-framework/event-feeder.h
new file mode 100644 (file)
index 0000000..2a10220
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __DALI_EVENT_FEEDER_H_
+#define __DALI_EVENT_FEEDER_H_
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+struct KeyEvent;
+struct WheelEvent;
+struct TouchPoint;
+
+namespace EventFeeder
+{
+
+/**
+ * Feed a touch point to the adaptor.
+ *
+ * @param[in] point touch point
+ * @param[in] timeStamp time value of event
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_IMPORT_API void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+/**
+ * Feed a wheel event to the adaptor.
+ *
+ * @param[in]  wheelEvent wheel event
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_IMPORT_API void FeedWheelEvent( WheelEvent& wheelEvent );
+
+/**
+ * Feed a key event to the adaptor.
+ *
+ * @param[in] keyEvent The key event holding the key information.
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_IMPORT_API void FeedKeyEvent( KeyEvent& keyEvent );
+
+} // namespace EventFeeder
+
+} // namespace Dali
+
+#endif // __DALI_EVENT_FEEDER_H_
diff --git a/adaptors/devel-api/adaptor-framework/feedback-player.cpp b/adaptors/devel-api/adaptor-framework/feedback-player.cpp
new file mode 100644 (file)
index 0000000..a43a0c0
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <feedback-player.h>
+
+// INTERNAL INCLUDES
+#include <feedback-player-impl.h>
+
+namespace Dali
+{
+
+FeedbackPlayer::FeedbackPlayer()
+{
+}
+
+FeedbackPlayer FeedbackPlayer::Get()
+{
+  return Internal::Adaptor::FeedbackPlayer::Get();
+}
+
+FeedbackPlayer::~FeedbackPlayer()
+{
+}
+
+void FeedbackPlayer::PlayMonotone(unsigned int duration)
+{
+  GetImplementation(*this).PlayMonotone(duration);
+}
+
+void FeedbackPlayer::PlayFile(const std::string filePath)
+{
+  GetImplementation(*this).PlayFile(filePath);
+}
+
+void FeedbackPlayer::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+int FeedbackPlayer::PlaySound( const std::string& fileName )
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+void FeedbackPlayer::StopSound( int handle )
+{
+  GetImplementation(*this).StopSound(handle);
+}
+
+void FeedbackPlayer::PlayFeedbackPattern( int type, int pattern )
+{
+  GetImplementation(*this).PlayFeedbackPattern(type, pattern);
+}
+
+bool FeedbackPlayer::LoadFile(const std::string& filename, std::string& data)
+{
+  return GetImplementation(*this).LoadFile(filename, data);
+}
+
+FeedbackPlayer::FeedbackPlayer( Internal::Adaptor::FeedbackPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/feedback-player.h b/adaptors/devel-api/adaptor-framework/feedback-player.h
new file mode 100644 (file)
index 0000000..0069df1
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef __DALI_FEEDBACK_PLAYER_H__
+#define __DALI_FEEDBACK_PLAYER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class FeedbackPlayer;
+}
+}
+
+/**
+ * @brief Plays feedback effects.
+ */
+class DALI_IMPORT_API FeedbackPlayer : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling FeedbackPlayer::Get().
+   */
+  FeedbackPlayer();
+
+  /**
+   * @brief Create an initialized handle to the FeedbackPlayer.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static FeedbackPlayer Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~FeedbackPlayer();
+
+  /**
+   * @brief Plays a monotone vibration.
+   * @param[in]  duration  The duration of the vibration.
+   */
+  void PlayMonotone(unsigned int duration);
+
+  /**
+   * @brief Plays vibration in predefined patterns.
+   * @param[in] filePath Path to the file containing the effect.
+   */
+  void PlayFile(const std::string filePath);
+
+  /**
+   * @brief Stops the currently playing vibration effects.
+   */
+  void Stop();
+
+  /**
+   * Plays a sound file.
+   * @param[in] fileName Path to the sound file to play.
+   * @return A handle which can be used to stop the sound playback.
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * Stops a currently playing sound.
+   * @param[in] handle A handle to the currently playing sound.
+   */
+  void StopSound( int handle );
+
+  /**
+   * Plays a feedback pattern.
+   * @param[in] type The type of feedback.
+   * @param[in] pattern The ID of the pattern to play.
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+  /*
+   * Loads a file into data
+   * @param[in] filename The filename.
+   * @param[in] data The data in the file.
+   * @return True if the file data could be loaded
+   */
+  bool LoadFile(const std::string& filename, std::string& data);
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by FeedbackPlayer::Get().
+   * @param[in] feedbackPlayer A pointer to the feedback player.
+   */
+  explicit DALI_INTERNAL FeedbackPlayer( Internal::Adaptor::FeedbackPlayer* feedbackPlayer );
+};
+
+} // namespace Dali
+
+#endif // __DALI_FEEDBACK_PLAYER_H__
diff --git a/adaptors/devel-api/adaptor-framework/feedback-plugin.h b/adaptors/devel-api/adaptor-framework/feedback-plugin.h
new file mode 100644 (file)
index 0000000..007ac1c
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef __DALI_FEEDBACK_PLUGIN_H__
+#define __DALI_FEEDBACK_PLUGIN_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+/**
+ * FeedbackPlugin is an abstract interface, used by Dali-adaptor to access haptic and audio feedback.
+ * A concrete implementation must be created for each platform and provided as a dynamic library which
+ * will be loaded at run time by the adaptor.
+ */
+class FeedbackPlugin
+{
+public:
+
+  typedef void (*SoundStopCallBack)( void* ptr );
+
+  /**
+   * Destructor.
+   */
+  virtual ~FeedbackPlugin()
+  {
+  }
+
+  /**
+   * Plays vibration in predefined patterns.
+   * @param[in] filePath Path to the file containing the effect.
+   */
+  virtual void PlayHaptic( const std::string& filePath ) = 0;
+
+  /**
+   * Plays a monotone vibration.
+   * @param[in]  duration  The duration of the vibration.
+   */
+  virtual void PlayHapticMonotone( unsigned int duration ) = 0;
+
+  /**
+   * Stops the currently playing vibration effects.
+   */
+  virtual void StopHaptic() = 0;
+
+  /**
+   * Plays a sound file.
+   * @param[in] fileName Path to the sound file to play.
+   * @return A handle which can be used to stop the sound playback.
+   */
+  virtual int PlaySound( const std::string& fileName ) = 0;
+
+  /**
+   * Stops a currently playing sound.
+   * @param[in] handle A handle to the currently playing sound.
+   */
+  virtual void StopSound( int handle ) = 0;
+
+  /**
+   * Plays a feedback pattern.
+   * @param[in] type The type of feedback.
+   * @param[in] pattern The ID of the pattern to play.
+   */
+  virtual void PlayFeedbackPattern( int type, int pattern ) = 0;
+
+  // Types for plugin factories
+
+  /**
+   * Function pointer called in adaptor to create a feedback plugin instance.
+   * @param [in] pluginName name of the plugin to load.
+   * @return Pointer to the newly created plugin object
+   */
+  typedef FeedbackPlugin* CreateFeedbackPlugin( void );
+
+}; // class FeedbackPlugin
+
+} // namespace Dali
+
+#endif // __DALI_FEEDBACK_PLUGIN_H__
diff --git a/adaptors/devel-api/adaptor-framework/imf-manager.cpp b/adaptors/devel-api/adaptor-framework/imf-manager.cpp
new file mode 100644 (file)
index 0000000..94d5fc1
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <imf-manager.h>
+
+// INTERNAL INCLUDES
+#include <imf-manager-impl.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+ImfManager::ImfManager()
+{
+}
+
+ImfManager::~ImfManager()
+{
+}
+
+ImfManager ImfManager::Get()
+{
+  return Internal::Adaptor::ImfManager::Get();
+}
+
+ImfContext ImfManager::GetContext()
+{
+  return reinterpret_cast<ImfContext>( Internal::Adaptor::ImfManager::GetImplementation(*this).GetContext() );
+}
+
+void ImfManager::Activate()
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).Activate();
+}
+
+void ImfManager::Deactivate()
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).Deactivate();
+}
+
+bool ImfManager::RestoreAfterFocusLost() const
+{
+  return Internal::Adaptor::ImfManager::GetImplementation(*this).RestoreAfterFocusLost();
+}
+
+void ImfManager::SetRestoreAfterFocusLost( bool toggle )
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).SetRestoreAfterFocusLost( toggle );
+}
+
+void ImfManager::Reset()
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).Reset();
+}
+
+void ImfManager::NotifyCursorPosition()
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).NotifyCursorPosition();
+}
+
+void ImfManager::SetCursorPosition( unsigned int SetCursorPosition )
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
+}
+
+int ImfManager::GetCursorPosition()
+{
+  return Internal::Adaptor::ImfManager::GetImplementation(*this).GetCursorPosition();
+}
+
+void ImfManager::SetSurroundingText( std::string text )
+{
+  Internal::Adaptor::ImfManager::GetImplementation(*this).SetSurroundingText( text );
+}
+
+std::string ImfManager::GetSurroundingText()
+{
+  return Internal::Adaptor::ImfManager::GetImplementation(*this).GetSurroundingText();
+}
+
+ImfManager::ImfManagerSignalType& ImfManager::ActivatedSignal()
+{
+  return Internal::Adaptor::ImfManager::GetImplementation(*this).ActivatedSignal();
+}
+
+ImfManager::ImfEventSignalType& ImfManager::EventReceivedSignal()
+{
+  return Internal::Adaptor::ImfManager::GetImplementation(*this).EventReceivedSignal();
+}
+
+ImfManager::ImfManager(Internal::Adaptor::ImfManager *impl)
+  : BaseHandle(impl)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/imf-manager.h b/adaptors/devel-api/adaptor-framework/imf-manager.h
new file mode 100644 (file)
index 0000000..00e589e
--- /dev/null
@@ -0,0 +1,257 @@
+#ifndef __DALI_IMF_MANAGER_H__
+#define __DALI_IMF_MANAGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class ImfManager;
+}
+}
+
+// TODO: Temporary patch to hidden ecore dependency. Must fix it.
+typedef void* ImfContext;
+
+/**
+ * @brief The ImfManager class
+ *
+ * Specifically manages the ecore input method framework which enables the virtual or hardware keyboards.
+ */
+class DALI_IMPORT_API ImfManager : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Events that are generated by the IMF.
+   */
+  enum ImfEvent
+  {
+    VOID,                ///< No event
+    PREEDIT,             ///< Pre-Edit changed
+    COMMIT,              ///< Commit recieved
+    DELETESURROUNDING,   ///< Event to delete a range of characters from the string
+    GETSURROUNDING       ///< Event to query string and cursor position
+  };
+
+  /**
+   * @brief This structure is used to pass on data from the IMF regarding predictive text.
+   */
+  struct ImfEventData
+  {
+    /**
+     * @brief Default Constructor.
+     */
+    ImfEventData()
+    : eventName( VOID ),
+      predictiveString(""),
+      cursorOffset( 0 ),
+      numberOfChars ( 0 )
+    {
+    };
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] aEventName The name of the event from the IMF.
+     * @param[in] aPredictiveString The pre-edit or commit string.
+     * @param[in] aCursorOffset Start position from the current cursor position to start deleting characters.
+     * @param[in] aNumberOfChars The number of characters to delete from the cursorOffset.
+     */
+    ImfEventData(ImfEvent aEventName, const std::string& aPredictiveString, int aCursorOffset,int aNumberOfChars  )
+    : eventName(aEventName), predictiveString(aPredictiveString), cursorOffset( aCursorOffset ), numberOfChars( aNumberOfChars )
+    {
+    }
+
+    // Data
+    ImfEvent eventName; ///< The name of the event from the IMF.
+    std::string predictiveString; ///< The pre-edit or commit string.
+    int cursorOffset; ///< Start position from the current cursor position to start deleting characters.
+    int numberOfChars; ///< number of characters to delete from the cursorOffset.
+  };
+
+  /**
+   * @brief Data required by IMF from the callback
+   */
+  struct ImfCallbackData
+  {
+    /**
+     * @brief Constructor
+     */
+    ImfCallbackData( )
+    : update( false ), cursorPosition( 0 ), preeditResetRequired ( false )
+    {
+    }
+
+    /**
+     * @brief Constructor
+     * @param[in] aUpdate True if cursor position needs to be updated
+     * @param[in] aCursorPosition new position of cursor
+     * @param[in] aCurrentText current text string
+     * @param[in] aPreeditResetRequired flag if preedit reset is required.
+     */
+    ImfCallbackData(bool aUpdate, int aCursorPosition, std::string aCurrentText, bool aPreeditResetRequired )
+    : update(aUpdate), cursorPosition(aCursorPosition), currentText( aCurrentText ), preeditResetRequired( aPreeditResetRequired )
+    {
+    }
+
+    bool update; ///< if cursor position needs to be updated
+    int cursorPosition; ///< new position of cursor
+    std::string currentText; ///< current text string
+    bool preeditResetRequired; ///< flag if preedit reset is required.
+  };
+
+  typedef Signal< void (ImfManager&) > ImfManagerSignalType; ///< Keyboard actived signal
+
+  typedef Signal< ImfCallbackData ( ImfManager&, const ImfEventData& ) > ImfEventSignalType; ///< keyboard events
+
+public:
+
+  /**
+   * @brief Retrieve a handle to the instance of ImfManager.
+   * @return A handle to the ImfManager.
+   */
+  static ImfManager Get();
+
+  /**
+   * @brief Get the current imf context.
+   * @return current imf context.
+   */
+  ImfContext GetContext();
+
+  /**
+   * @brief Activate the IMF.
+   *
+   * It means that the text editing is started at somewhere.
+   * If the H/W keyboard isn't connected then it will show the virtual keyboard.
+   */
+  void Activate();
+
+  /**
+   * @brief Deactivate the IMF.
+   *
+   * It means that the text editing is finished at somewhere.
+   */
+  void Deactivate();
+
+  /**
+   * @brief Get the restoration status, which controls if the keyboard is restored after the focus lost then regained.
+   *
+   * If true then keyboard will be restored (activated) after focus is regained.
+   * @return restoration status.
+   */
+  bool RestoreAfterFocusLost() const;
+
+  /**
+   * @brief Set status whether the IMF has to restore the keyboard after losing focus.
+   *
+   * @param[in] toggle True means that keyboard should be restored after focus lost and regained.
+   */
+  void SetRestoreAfterFocusLost( bool toggle );
+
+  /**
+   * @brief Send message reset the pred-edit state / imf module.
+   *
+   * Used to interupt pre-edit state maybe due to a touch input.
+   */
+  void Reset();
+
+  /**
+   * @brief Notifies IMF context that the cursor position has changed, required for features like auto-capitalisation.
+   */
+  void NotifyCursorPosition();
+
+  /**
+   * @brief Sets cursor position stored in VirtualKeyboard, this is required by the IMF context.
+   *
+   * @param[in] cursorPosition position of cursor
+   */
+  void SetCursorPosition( unsigned int cursorPosition );
+
+  /**
+   * @brief Gets cursor position stored in VirtualKeyboard, this is required by the IMF context.
+   *
+   * @return current position of cursor
+   */
+  int GetCursorPosition();
+
+  /**
+   * @brief Method to store the string required by the IMF, this is used to provide predictive word suggestions.
+   *
+   * @param[in] text The text string surrounding the current cursor point.
+   */
+  void SetSurroundingText( std::string text );
+
+  /**
+   * @brief Gets current text string set within the IMF manager, this is used to offer predictive suggestions.
+   *
+   * @return current position of cursor
+   */
+  std::string GetSurroundingText();
+
+public:
+
+  // Signals
+
+  /**
+   * @brief This is emitted when the virtual keyboard is connected to or the hardware keyboard is activated.
+   *
+   * @return The IMF Activated signal.
+   */
+  ImfManagerSignalType& ActivatedSignal();
+
+  /**
+   * @brief This is emitted when the IMF manager receives an event from the IMF.
+   *
+   * @return The Event signal containing the event data.
+   */
+  ImfEventSignalType& EventReceivedSignal();
+
+  // Construction & Destruction
+
+  /**
+   * @brief Constructor.
+   */
+  ImfManager();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ImfManager();
+
+  /**
+   * @brief This constructor is used by ImfManager::Get().
+   *
+   * @param[in] imfManager A pointer to the imf Manager.
+   */
+  explicit DALI_INTERNAL ImfManager( Internal::Adaptor::ImfManager* imfManager );
+};
+
+} // namespace Dali
+
+#endif // __DALI_IMF_MANAGER_H__
diff --git a/adaptors/devel-api/adaptor-framework/lifecycle-controller.cpp b/adaptors/devel-api/adaptor-framework/lifecycle-controller.cpp
new file mode 100644 (file)
index 0000000..c65724e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <lifecycle-controller.h>
+
+// INTERNAL INCLUDES
+#include <lifecycle-controller-impl.h>
+
+namespace Dali
+{
+
+LifecycleController::LifecycleController()
+{
+}
+
+LifecycleController::LifecycleController(const LifecycleController& controller)
+: BaseHandle(controller)
+{
+}
+
+LifecycleController LifecycleController::Get()
+{
+  return Internal::Adaptor::LifecycleController::Get();
+}
+
+LifecycleController::~LifecycleController()
+{
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  return GetImplementation(*this).InitSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::TerminateSignal()
+{
+  return GetImplementation(*this).TerminateSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::PauseSignal()
+{
+  return GetImplementation(*this).PauseSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResumeSignal()
+{
+  return GetImplementation(*this).ResumeSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResetSignal()
+{
+  return GetImplementation(*this).ResetSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResizeSignal()
+{
+  return GetImplementation(*this).ResizeSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::LanguageChangedSignal()
+{
+  return GetImplementation(*this).LanguageChangedSignal();
+}
+
+LifecycleController& LifecycleController::operator=(const LifecycleController& monitor)
+{
+  if( *this != monitor )
+  {
+    BaseHandle::operator=(monitor);
+  }
+  return *this;
+}
+
+LifecycleController::LifecycleController(Internal::Adaptor::LifecycleController* internal)
+: BaseHandle(internal)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/lifecycle-controller.h b/adaptors/devel-api/adaptor-framework/lifecycle-controller.h
new file mode 100644 (file)
index 0000000..a818f54
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef __DALI_LIFECYCLE_CONTROLLER_H__
+#define __DALI_LIFECYCLE_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class LifecycleController;
+}
+}
+
+/**
+ * @brief Provides application lifecycle events.
+ *
+ * Connect to the signals of this class to receive notification of events in the lifecycle
+ * of the application. The following example shows how to connect to the Init signal. This
+ * could be done for example in the constructor of a singleton that is known to be created
+ * at startup.
+ *
+ * @code
+ * void MyClass::MyClass()
+ * {
+ *   LifecycleController::Get().InitSignal().Connect( this, &MyClass::OnApplicationInit );
+ * }
+ *
+ * void MyClass::OnApplicationInit()
+ * {
+ *   // ... Do something on init
+ * }
+ * @endcode
+ */
+class DALI_IMPORT_API LifecycleController : public BaseHandle
+{
+public: // Typedefs
+
+  typedef Signal< void (void) > LifecycleSignalType;   ///< Lifecycle Signal type
+
+public: // Creation & Destruction
+
+  /**
+   * @brief Create an uninitialized LifecycleController handle.
+   *
+   * Calling member functions when uninitialized is not allowed.
+   */
+  LifecycleController();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  monitor  The LifecycleController to copy from.
+   */
+  LifecycleController(const LifecycleController& monitor);
+
+  /**
+   * @brief Retrieve the initialized instance of the LifecycleController.
+   * @return Handle to LifecycleController.
+   */
+  static LifecycleController Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~LifecycleController();
+
+public: // Signals
+
+  /**
+   * The user should connect to this signal to determine when they should initialise
+   * their application.
+   */
+  LifecycleSignalType& InitSignal();
+
+  /**
+   * The user should connect to this signal to determine when they should terminate
+   * their application
+   */
+  LifecycleSignalType& TerminateSignal();
+
+  /**
+   * The user should connect to this signal if they need to perform any special
+   * activities when the application is about to be paused.
+   */
+  LifecycleSignalType& PauseSignal();
+
+  /**
+   * The user should connect to this signal if they need to perform any special
+   * activities when the application has resumed.
+   */
+  LifecycleSignalType& ResumeSignal();
+
+  /**
+   * This signal is sent when the system requires the user to reinitialise itself.
+   */
+  LifecycleSignalType& ResetSignal();
+
+  /**
+   * This signal is emitted when the window the application is rendering on is resized.
+   */
+  LifecycleSignalType& ResizeSignal();
+
+  /**
+   * This signal is emitted when the language is changed on the device.
+   */
+  LifecycleSignalType& LanguageChangedSignal();
+
+public: // Operators
+
+  /**
+   * @brief Assignment operator.
+   *
+   * The handle points to the same implementation as the one being copied from.
+   * @param[in]  controller  The LifecycleController to copy from.
+   * @return reference to this object
+   */
+  LifecycleController& operator=(const LifecycleController& controller);
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] lifecycleController A pointer to the internal LifecycleController.
+   */
+  explicit DALI_INTERNAL LifecycleController(Internal::Adaptor::LifecycleController* lifecycleController);
+};
+
+} // namespace Dali
+
+#endif // __DALI_LIFECYCLE_CONTROLLER_H__
diff --git a/adaptors/devel-api/adaptor-framework/orientation.cpp b/adaptors/devel-api/adaptor-framework/orientation.cpp
new file mode 100644 (file)
index 0000000..72cb405
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <orientation.h>
+
+// INTERNAL INCLUDES
+#include <orientation-impl.h>
+
+namespace Dali
+{
+
+Orientation::Orientation()
+{
+}
+
+Orientation::~Orientation()
+{
+}
+
+Orientation::Orientation(const Orientation& handle)
+: BaseHandle(handle)
+{
+}
+
+Orientation& Orientation::operator=(const Orientation& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+int Orientation::GetDegrees() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetDegrees();
+}
+
+float Orientation::GetRadians() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetRadians();
+}
+
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ChangedSignal();
+}
+
+Orientation::Orientation( Internal::Adaptor::Orientation* orientation )
+: BaseHandle(orientation)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/orientation.h b/adaptors/devel-api/adaptor-framework/orientation.h
new file mode 100644 (file)
index 0000000..603063a
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef __DALI_ORIENTATION_H__
+#define __DALI_ORIENTATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Orientation;
+}
+}
+
+/**
+ * @brief Orientation allows the user to determine the orientation of the device.
+ *
+ * A signal is emitted whenever the orientation changes.
+ * Dali applications have full control over visual layout when the device is rotated
+ * i.e. the application developer decides which UI controls to rotate, if any.
+ */
+class DALI_IMPORT_API Orientation : public BaseHandle
+{
+public:
+
+  typedef Signal< void (Orientation) > OrientationSignalType; ///< Orientation changed signal type
+
+  /**
+   * @brief Create an unintialized handle.
+   *
+   * This can be initialized by calling Dali::Application::GetOrientation()
+   */
+  Orientation();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Orientation();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  Orientation(const Orientation& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  Orientation& operator=(const Orientation& rhs);
+
+  /**
+   * @brief Returns the orientation of the device in degrees.
+   *
+   * This is one of four discrete values, in degrees clockwise: 0, 90, 180, & 270
+   * For a device with a portrait form-factor:
+   *   0 indicates that the device is in the "normal" portrait orientation.
+   *   90 indicates that device has been rotated clockwise, into a landscape orientation.
+   * @return The orientation in degrees clockwise.
+   */
+  int GetDegrees() const;
+
+  /**
+   * @brief Returns the orientation of the device in radians.
+   *
+   * This is one of four discrete values, in radians clockwise: 0, PI/2, PI, & 3xPI/2
+   * For a device with a portrait form-factor:
+   *   0 indicates that the device is in the "normal" portrait orientation.
+   *   PI/2 indicates that device has been rotated clockwise, into a landscape orientation.
+   * @return The orientation in radians clockwise.
+   */
+  float GetRadians() const;
+
+  /**
+   * @brief The user should connect to this signal so that they can be notified whenever
+   * the orientation of the device changes.
+   *
+   * @return The orientation change signal.
+   */
+  OrientationSignalType& ChangedSignal();
+
+public: // Not intended for application developers
+  /**
+   * @brief Helper function.
+   *
+   * @param[in] orientation A pointer to the orientation object
+   */
+  explicit DALI_INTERNAL Orientation( Internal::Adaptor::Orientation* orientation );
+};
+
+} // namespace Dali
+
+#endif // __DALI_ORIENTATION_H__
diff --git a/adaptors/devel-api/adaptor-framework/performance-logger.cpp b/adaptors/devel-api/adaptor-framework/performance-logger.cpp
new file mode 100644 (file)
index 0000000..9cb0445
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <performance-logger.h>
+
+// INTERNAL INCLUDES
+#include <performance-logger-impl.h>
+
+namespace Dali
+{
+
+PerformanceLogger::PerformanceLogger()
+{
+}
+
+PerformanceLogger PerformanceLogger::New( const char* name )
+{
+  Internal::Adaptor::PerformanceLoggerPtr internal = Internal::Adaptor::PerformanceLogger::New( name );
+  return PerformanceLogger(internal.Get());
+}
+
+PerformanceLogger::PerformanceLogger( const PerformanceLogger& performanceLogger )
+: BaseHandle(performanceLogger)
+{
+}
+
+PerformanceLogger& PerformanceLogger::operator=( const PerformanceLogger& performanceLogger )
+{
+  // check self assignment
+  if( *this != performanceLogger )
+  {
+    BaseHandle::operator=(performanceLogger);
+  }
+  return *this;
+}
+
+PerformanceLogger::~PerformanceLogger()
+{
+}
+
+PerformanceLogger PerformanceLogger::DownCast( BaseHandle handle )
+{
+  return PerformanceLogger( dynamic_cast<Internal::Adaptor::PerformanceLogger*>( handle.GetObjectPtr() ) );
+}
+
+void PerformanceLogger::AddMarker( Marker markerType )
+{
+  Internal::Adaptor::GetImplementation(*this).AddMarker( markerType );
+}
+
+void PerformanceLogger::SetLoggingFrequency( unsigned int logFrequency)
+{
+  Internal::Adaptor::GetImplementation(*this).SetLoggingFrequency( logFrequency );
+}
+
+void PerformanceLogger::EnableLogging( bool enable )
+{
+  Internal::Adaptor::GetImplementation(*this).EnableLogging( enable );
+}
+
+PerformanceLogger::PerformanceLogger(Internal::Adaptor::PerformanceLogger* PerformanceLogger)
+: BaseHandle(PerformanceLogger)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/performance-logger.h b/adaptors/devel-api/adaptor-framework/performance-logger.h
new file mode 100644 (file)
index 0000000..30992d0
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef __DALI_PERFORMANCE_LOGGER_H__
+#define __DALI_PERFORMANCE_LOGGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class PerformanceLogger;
+}
+}
+
+/**
+ * @brief Performance logger class
+ */
+class DALI_IMPORT_API PerformanceLogger : public BaseHandle
+{
+public:
+
+  /**
+   * Enum for events that can be logged
+   */
+  enum Marker
+  {
+    START_EVENT,      ///< The start of timing
+    END_EVENT         ///< The end of timing
+  };
+
+  /**
+   * @brief Constructor, creates an uninitialized logger.
+   *
+   * Call New to fully construct a logger.
+   */
+  PerformanceLogger();
+
+  /**
+   * @brief Create a new logger
+   *
+   * @param[in] name The name of the logger. This needs to be a compile-time literal and alive for the whole lifetime of the performance logger.
+   * @return a new logger
+   */
+  static PerformanceLogger New( const char* name );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] logger The handle to copy. The copied handle will point at the same implementation
+   */
+  PerformanceLogger( const PerformanceLogger& logger );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] logger The handle to copy. This handle will point at the same implementation
+   * as the copied handle.
+   * @return Reference to this logger handle
+   */
+  PerformanceLogger& operator=( const PerformanceLogger& logger );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~PerformanceLogger();
+
+  /**
+   * @brief Downcast an Object handle to PerformanceLogger handle.
+   *
+   * If handle points to a PerformanceLogger object the downcast produces a valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object
+   * @return handle to a PerformanceLogger object or an uninitialized handle
+   */
+  static PerformanceLogger DownCast( BaseHandle handle );
+
+  /**
+   * Add a performance marker
+   *
+   * @param markerType Performance marker type
+   */
+  void AddMarker( Marker markerType );
+
+  /**
+   * Set the logging frequency
+   *
+   * @param logFrequency how often to log out in seconds
+   */
+  void SetLoggingFrequency( unsigned int logFrequency);
+
+  /**
+   * Set logging on or off for this logger
+   *
+   * @param[in] enable Enable logging or not
+   */
+  void EnableLogging( bool enable );
+
+  // Not intended for application developers
+
+  /**
+   * Creates a new handle from the implementation.
+   * @param[in] impl A pointer to the object.
+   */
+  explicit DALI_INTERNAL PerformanceLogger( Internal::Adaptor::PerformanceLogger* impl );
+
+};
+
+} // namespace Dali
+
+#endif // __DALI_PERFORMANCE_LOGGER_H__
diff --git a/adaptors/devel-api/adaptor-framework/physical-keyboard.cpp b/adaptors/devel-api/adaptor-framework/physical-keyboard.cpp
new file mode 100644 (file)
index 0000000..d34ff0c
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <physical-keyboard.h>
+
+// INTERNAL INCLUDES
+#include <physical-keyboard-impl.h>
+
+namespace Dali
+{
+
+PhysicalKeyboard::PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard::~PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  // Get the physical keyboard handle
+  PhysicalKeyboard handle = Internal::Adaptor::PhysicalKeyboard::Get();
+
+  // If it's not been created then create one
+  if ( !handle )
+  {
+    handle = Internal::Adaptor::PhysicalKeyboard::New();
+  }
+
+  return handle;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  return GetImplementation( *this ).IsAttached();
+}
+
+PhysicalKeyboard::PhysicalKeyboardSignalType& PhysicalKeyboard::StatusChangedSignal()
+{
+  return GetImplementation( *this ).StatusChangedSignal();
+}
+
+PhysicalKeyboard::PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard *impl )
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/physical-keyboard.h b/adaptors/devel-api/adaptor-framework/physical-keyboard.h
new file mode 100644 (file)
index 0000000..3d53913
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef __DALI_PHYSICAL_KEYBOARD_H__
+#define __DALI_PHYSICAL_KEYBOARD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class PhysicalKeyboard;
+}
+}
+
+/**
+ * This is a handle to a physical keyboard connected to the device.
+ */
+class DALI_IMPORT_API PhysicalKeyboard : public BaseHandle
+{
+public:
+
+  typedef Signal< void (PhysicalKeyboard) > PhysicalKeyboardSignalType;
+
+public:
+
+  /**
+   * Create an uninitialized PhysicalKeyboard handle; this can be initialized with GetKeyboard()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  PhysicalKeyboard();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~PhysicalKeyboard();
+
+  /**
+   * Gets a handle to the physical keyboard.
+   * @return A handle to the physical keyboard.
+   */
+  static PhysicalKeyboard Get();
+
+  /**
+   * Queries whether a physical keyboard is attached or not.
+   * @return true if a physical keyboard is attached, false otherwise.
+   */
+  bool IsAttached() const;
+
+  // Signals
+
+  /**
+   * Emitted when the status of the physical keyboard changes.
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(PhysicalKeyboard keyboard);
+   * @endcode
+   * @pre The PhysicalKeyboard has been initialized.
+   * @return The status changed signal.
+   */
+  PhysicalKeyboardSignalType& StatusChangedSignal();
+
+  // Not intended for application developers
+
+  /**
+   * Creates a new handle from the implementation.
+   * @param[in] impl A pointer to the object.
+   */
+  explicit DALI_INTERNAL PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard* impl );
+};
+
+} // namespace Dali
+
+#endif // __DALI_PHYSICAL_KEYBOARD_H__
diff --git a/adaptors/devel-api/adaptor-framework/render-surface.h b/adaptors/devel-api/adaptor-framework/render-surface.h
new file mode 100644 (file)
index 0000000..2844105
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef __DALI_RENDER_SURFACE_H__
+#define __DALI_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/view-mode.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+class EglInterface;
+class DisplayConnection;
+class ThreadSynchronizationInterface;
+
+namespace Integration
+{
+
+class GlAbstraction;
+
+} // namespace Integration
+
+/**
+ * @brief The position and size of the render surface.
+ */
+typedef Dali::Rect<int> PositionSize;
+
+/**
+ * @brief Interface for a render surface onto which Dali draws.
+ *
+ * Dali::Adaptor requires a render surface to draw on to. This is
+ * usually a window in the native windowing system, or some other
+ * mapped pixel buffer.
+ *
+ * Dali::Application will automatically create a render surface using a window.
+ *
+ * The implementation of the factory method below should choose an appropriate
+ * implementation of RenderSurface for the given platform
+ */
+
+class RenderSurface
+{
+public:
+
+  /**
+   * @brief Constructor
+   * Inlined as this is a pure abstract interface
+   */
+  RenderSurface() {}
+
+  /**
+   * @brief Virtual Destructor.
+   * Inlined as this is a pure abstract interface
+   */
+  virtual ~RenderSurface() {}
+
+  /**
+   * @brief Return the size and position of the surface.
+   * @return The position and size
+   */
+  virtual PositionSize GetPositionSize() const = 0;
+
+  /**
+   * Initialize EGL, RenderSurface should create egl display and initialize
+   * @param egl implementation to use for the creation
+   */
+  virtual void InitializeEgl( EglInterface& egl ) = 0;
+
+  /**
+   * @brief Creates EGL Surface
+   * @param egl implementation to use for the creation
+   */
+  virtual void CreateEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @brief Destroys EGL Surface
+   * @param egl implementation to use for the destruction
+   */
+  virtual void DestroyEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @brief Replace the EGL Surface
+   * @param egl implementation to use for the creation
+   * @return true if context was lost
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @brief Resizes the underlying surface. Only available for x window
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @brief Set the stereoscopic 3D view mode
+   * @param[in] viewMode The new view mode
+   */
+  virtual void SetViewMode( ViewMode viewMode ) = 0;
+
+  /**
+   * @brief Called when Render thread has started
+   */
+  virtual void StartRender() = 0;
+
+  /**
+   * @brief Invoked by render thread before Core::Render
+   * If the operation fails, then Core::Render should not be called until there is
+   * a surface to render onto.
+   * @param[in] egl The Egl interface
+   * @param[in] glAbstraction OpenGLES abstraction interface
+   * @return True if the operation is successful, False if the operation failed
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) = 0;
+
+  /**
+   * @brief Invoked by render thread after Core::Render
+   * @param[in] egl The Egl interface
+   * @param[in] glAbstraction OpenGLES abstraction interface
+   * @param[in] displayConnection display connection
+   * @param[in] replacingSurface True if the surface is being replaced.
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface ) = 0;
+
+  /**
+   * @brief Invoked by render thread when the thread should be stop
+   */
+  virtual void StopRender() = 0;
+
+  /**
+   * @brief Invoked by Event Thread when the compositor lock should be released and rendering should resume.
+   */
+  virtual void ReleaseLock() = 0;
+
+  /**
+   * @brief Sets the ThreadSynchronizationInterface
+   *
+   * @param threadSynchronization The thread-synchronization implementation.
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) = 0;
+
+private:
+
+  /**
+   * @brief Undefined copy constructor. RenderSurface cannot be copied
+   */
+  RenderSurface( const RenderSurface& rhs );
+
+  /**
+   * @brief Undefined assignment operator. RenderSurface cannot be copied
+   */
+  RenderSurface& operator=( const RenderSurface& rhs );
+};
+
+} // namespace Dali
+
+#endif // __DALI_RENDER_SURFACE_H__
diff --git a/adaptors/devel-api/adaptor-framework/singleton-service.cpp b/adaptors/devel-api/adaptor-framework/singleton-service.cpp
new file mode 100644 (file)
index 0000000..a630d12
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+SingletonService::SingletonService()
+{
+}
+
+SingletonService SingletonService::New()
+{
+  return Internal::Adaptor::SingletonService::New();
+}
+
+SingletonService SingletonService::Get()
+{
+  return Internal::Adaptor::SingletonService::Get();
+}
+
+SingletonService::~SingletonService()
+{
+}
+
+void SingletonService::Register( const std::type_info& info, BaseHandle singleton )
+{
+  GetImplementation( *this ).Register( info, singleton );
+}
+
+void SingletonService::UnregisterAll()
+{
+  GetImplementation( *this ).UnregisterAll();
+}
+
+BaseHandle SingletonService::GetSingleton( const std::type_info& info ) const
+{
+  return GetImplementation( *this ).GetSingleton( info );
+}
+
+SingletonService::SingletonService( Internal::Adaptor::SingletonService* singletonService )
+: BaseHandle( singletonService )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/singleton-service.h b/adaptors/devel-api/adaptor-framework/singleton-service.h
new file mode 100644 (file)
index 0000000..5156f45
--- /dev/null
@@ -0,0 +1,114 @@
+#ifndef __DALI_SINGELTON_SERVICE_H__
+#define __DALI_SINGELTON_SERVICE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <typeinfo>
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class SingletonService;
+}
+}
+
+/**
+ * @brief Allows the registration of a class as a singleton
+ *
+ * @note This class is created by the Application class and is destroyed when the Application class is destroyed.
+ *
+ * @see Application
+ */
+class DALI_IMPORT_API SingletonService : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling SingletonService::Get().
+   */
+  SingletonService();
+
+  /**
+   * Create a SingletonService.
+   * This should only be called once by the Application class.
+   * @return A newly created SingletonService.
+   */
+  static Dali::SingletonService New();
+
+  /**
+   * @brief Retrieves a handle to the SingletonService.
+   *
+   * @return A handle to the SingletonService if it is available. This will be an empty handle if
+   *         the service is not available.
+   */
+  static SingletonService Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~SingletonService();
+
+  /**
+   * @brief Registers the singleton of Dali handle with its type info.
+   *
+   * The singleton will be kept alive for the lifetime of the service.
+   *
+   * @note This is not intended for application developers.
+   * @param[in] info The type info of the Dali handle generated by the compiler.
+   * @param[in] singleton The Dali handle to be registered
+   */
+  void Register( const std::type_info& info, BaseHandle singleton );
+
+  /**
+   * @brief Unregisters all singletons.
+   *
+   * @note This is not intended for application developers.
+   */
+  void UnregisterAll();
+
+  /**
+   * @brief Gets the singleton for the given type.
+   *
+   * @note This is not intended for application developers.
+   * @param[in] info The type info of the given type.
+   * @return the Dali handle if it is registered as a singleton or an uninitialized handle.
+   */
+  BaseHandle GetSingleton( const std::type_info& info ) const;
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by SingletonService::Get().
+   * @param[in] singletonService A pointer to the internal singleton-service object.
+   */
+  explicit DALI_INTERNAL SingletonService( Internal::Adaptor::SingletonService* singletonService );
+};
+
+} // namespace Dali
+
+#endif // __DALI_SINGELTON_SERVICE_H__
diff --git a/adaptors/devel-api/adaptor-framework/sound-player.cpp b/adaptors/devel-api/adaptor-framework/sound-player.cpp
new file mode 100644 (file)
index 0000000..a138793
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <sound-player.h>
+
+// INTERNAL INCLUDES
+#include <sound-player-impl.h>
+
+namespace Dali
+{
+
+SoundPlayer::SoundPlayer()
+{
+}
+
+SoundPlayer SoundPlayer::Get()
+{
+  return Internal::Adaptor::SoundPlayer::Get();
+}
+
+SoundPlayer::~SoundPlayer()
+{
+}
+
+int SoundPlayer::PlaySound(const std::string fileName)
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+void SoundPlayer::Stop(int handle)
+{
+  GetImplementation(*this).Stop(handle);
+}
+
+SoundPlayer::SoundPlayFinishedSignalType& SoundPlayer::SoundPlayFinishedSignal()
+{
+  return GetImplementation(*this).SoundPlayFinishedSignal();
+}
+
+SoundPlayer::SoundPlayer( Internal::Adaptor::SoundPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/sound-player.h b/adaptors/devel-api/adaptor-framework/sound-player.h
new file mode 100644 (file)
index 0000000..2766281
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef __DALI_SOUND_PLAYER_H__
+#define __DALI_SOUND_PLAYER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class SoundPlayer;
+}
+}
+
+/**
+ * @brief Plays sound effects.
+ */
+class DALI_IMPORT_API SoundPlayer : public BaseHandle
+{
+public:
+
+  typedef Signal< void (SoundPlayer&) > SoundPlayFinishedSignalType; ///< Sound play finished signal
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling SoundPlayer::Get().
+   */
+  SoundPlayer();
+
+  /**
+   * @brief Create an initialized handle to the SoundPlayer.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static SoundPlayer Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~SoundPlayer();
+
+  /**
+   * @brief Plays a sound file.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @param[in]  fileName Path to the sound file to play.
+   * @return a handle to the currently playing sound file which can be used to stop.
+   */
+  int PlaySound(const std::string fileName);
+
+  /**
+   * @brief Stops the currently playing sound.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @param[in] handle
+   */
+  void Stop(int handle);
+
+  /**
+   * @brief This signal will be emitted after a given sound file is completely played.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @return The signal to connect to.
+   *
+   * @note The signal name is "sound-play-finished" if using BaseHandle::ConnectSignal()
+   */
+  SoundPlayFinishedSignalType& SoundPlayFinishedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by SoundPlayer::Get().
+   *
+   * @param[in] soundPlayer A pointer to the sound player.
+   */
+  explicit DALI_INTERNAL SoundPlayer( Internal::Adaptor::SoundPlayer* soundPlayer );
+};
+
+} // namespace Dali
+
+#endif // __DALI_SOUND_PLAYER_H__
diff --git a/adaptors/devel-api/adaptor-framework/style-monitor.cpp b/adaptors/devel-api/adaptor-framework/style-monitor.cpp
new file mode 100644 (file)
index 0000000..4b08a2b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <style-monitor.h>
+
+// INTERNAL INCLUDES
+#include <style-monitor-impl.h>
+
+namespace Dali
+{
+
+StyleMonitor::StyleMonitor()
+{
+}
+
+StyleMonitor::StyleMonitor(const StyleMonitor& monitor)
+: BaseHandle(monitor)
+{
+}
+
+StyleMonitor StyleMonitor::StyleMonitor::Get()
+{
+  return Internal::Adaptor::StyleMonitor::Get();
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+StyleMonitor StyleMonitor::DownCast( BaseHandle handle )
+{
+  return StyleMonitor( dynamic_cast<Internal::Adaptor::StyleMonitor*>( handle.GetObjectPtr() ) );
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return GetImplementation(*this).GetDefaultFontFamily();
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return GetImplementation(*this).GetDefaultFontStyle();
+}
+
+int StyleMonitor::GetDefaultFontSize() const
+{
+  return GetImplementation(*this).GetDefaultFontSize();
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return GetImplementation(*this).GetTheme();
+}
+
+void StyleMonitor::SetTheme(const std::string& themFilePath)
+{
+  return GetImplementation(*this).SetTheme(themFilePath);
+}
+
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  return GetImplementation(*this).LoadThemeFile( filename, output );
+}
+
+StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
+{
+  return GetImplementation(*this).StyleChangeSignal();
+}
+
+StyleMonitor& StyleMonitor::operator=(const StyleMonitor& monitor)
+{
+  if( *this != monitor )
+  {
+    BaseHandle::operator=(monitor);
+  }
+  return *this;
+}
+
+StyleMonitor::StyleMonitor(Internal::Adaptor::StyleMonitor* internal)
+: BaseHandle(internal)
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/style-monitor.h b/adaptors/devel-api/adaptor-framework/style-monitor.h
new file mode 100644 (file)
index 0000000..bf63048
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef __DALI_STYLE_MONITOR_H__
+#define __DALI_STYLE_MONITOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#ifdef DALI_ADAPTOR_COMPILATION  // full path doesn't exist until adaptor is installed so we have to use relative
+// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
+#include <style-change.h>
+#else
+#include <dali/public-api/adaptor-framework/style-change.h>
+#endif
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class StyleMonitor;
+}
+}
+
+/**
+ * @brief Monitors the platform for style changes.
+ *
+ * This is a handle to the adaptor's style monitor which holds the platform's style information.
+ * It provides a signal when any aspect of the default style changes on the device.
+ * @see Adaptor::GetStyleMonitor
+ */
+class DALI_IMPORT_API StyleMonitor : public BaseHandle
+{
+public: // Typedefs
+
+  typedef Signal< void ( StyleMonitor, StyleChange::Type ) > StyleChangeSignalType;   ///< StyleChange Signal type
+
+public: // Creation & Destruction
+
+  /**
+   * @brief Create an uninitialized StyleMonitor handle.
+   *
+   * Tthis can be set by retrieving the style monitor from the Adaptor
+   * or the Application classes.  Calling member functions when
+   * uninitialized is not allowed.
+   */
+  StyleMonitor();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  monitor  The Style Monitor to copy from.
+   */
+  StyleMonitor(const StyleMonitor& monitor);
+
+  /**
+   * @brief Retrieve the initialized instance of the StyleMonitor.
+   * @return Handle to StyleMonitor.
+   */
+  static StyleMonitor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~StyleMonitor();
+
+  /**
+   * @brief Downcast an Object handle to StyleMonitor handle.
+   *
+   * If handle points to a StyleMonitor object the downcast produces a
+   * valid handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object @return handle to a Timer object
+   * or an uninitialized handle
+   */
+  static StyleMonitor DownCast( BaseHandle handle );
+
+public: // Style Information
+
+  /**
+   * @brief Retrieves the default font family.
+   * @return The default font family.
+   */
+  std::string GetDefaultFontFamily() const;
+
+  /**
+   * @brief Retrieves the default font style.
+   * @return The default font style.
+   */
+  std::string GetDefaultFontStyle() const;
+
+  /**
+   * @brief Retrieves the default font size.
+   *
+   * This is an logical size, which is mapped to a UI Control specific point-size in stylesheets.
+   * For example if zero the smallest size, this could potentially map to TextLabel point-size 8.
+   * @return The default font size, or a negative value if not set.
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @brief Retrieves the user defined Theme.
+   * @return The user defined Theme.
+   */
+  const std::string& GetTheme() const;
+
+  /**
+   * @brief Sets an user defined Theme.
+   * @param[in] themeFilePath Path of the user defined theme
+   */
+  void SetTheme(const std::string& themeFilePath);
+
+  /**
+   * @brief Utility to load a theme file
+   * @param filename of the theme
+   * @param output to write the contents to
+   * @return true if the load is successful
+   */
+  bool LoadThemeFile( const std::string& filename, std::string& output );
+
+public: // Signals
+
+  /**
+   * @brief This signal is emitted whenever the style changes on the device.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(StyleMonitor styleMonitor, StyleChange change);
+   * @endcode
+   * @return The signal to connect to.
+   */
+  StyleChangeSignalType& StyleChangeSignal();
+
+public: // Operators
+
+  /**
+   * @brief Assignment operator.
+   *
+   * The handle points to the same implementation as the one being copied from.
+   * @param[in]  monitor  The Style Monitor to copy from.
+   * @return reference to this object
+   */
+  StyleMonitor& operator=(const StyleMonitor& monitor);
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] styleMonitor A pointer the internal style monitor.
+   */
+  explicit DALI_INTERNAL StyleMonitor(Internal::Adaptor::StyleMonitor* styleMonitor);
+};
+
+} // namespace Dali
+
+#endif // __DALI_STYLE_MONITOR_H__
diff --git a/adaptors/devel-api/adaptor-framework/tilt-sensor.cpp b/adaptors/devel-api/adaptor-framework/tilt-sensor.cpp
new file mode 100644 (file)
index 0000000..f7eac57
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tilt-sensor.h"
+
+// INTERNAL INCLUDES
+#include <tilt-sensor-impl.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+const float TiltSensor::DEFAULT_UPDATE_FREQUENCY = 60.0f;
+
+TiltSensor::TiltSensor()
+{
+}
+
+TiltSensor TiltSensor::Get()
+{
+  return Internal::Adaptor::TiltSensor::Get();
+}
+
+TiltSensor::~TiltSensor()
+{
+}
+
+bool TiltSensor::Enable()
+{
+  return GetImplementation(*this).Enable();
+}
+
+void TiltSensor::Disable()
+{
+  GetImplementation(*this).Disable();
+}
+
+bool TiltSensor::IsEnabled() const
+{
+  return GetImplementation(*this).IsEnabled();
+}
+
+float TiltSensor::GetRoll() const
+{
+  return GetImplementation(*this).GetRoll();
+}
+
+float TiltSensor::GetPitch() const
+{
+  return GetImplementation(*this).GetPitch();
+}
+
+Quaternion TiltSensor::GetRotation() const
+{
+  return GetImplementation(*this).GetRotation();
+}
+
+TiltSensor::TiltedSignalType& TiltSensor::TiltedSignal()
+{
+  return GetImplementation(*this).TiltedSignal();
+}
+
+void TiltSensor::SetUpdateFrequency( float frequencyHertz )
+{
+  GetImplementation(*this).SetUpdateFrequency( frequencyHertz );
+}
+
+float TiltSensor::GetUpdateFrequency() const
+{
+  return GetImplementation(*this).GetUpdateFrequency();
+}
+
+void TiltSensor::SetRotationThreshold(Radian rotationThreshold)
+{
+  GetImplementation(*this).SetRotationThreshold( rotationThreshold );
+}
+
+Radian TiltSensor::GetRotationThreshold() const
+{
+  return GetImplementation(*this).GetRotationThreshold();
+}
+
+TiltSensor::TiltSensor( Internal::Adaptor::TiltSensor* sensor )
+: BaseHandle( sensor )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/tilt-sensor.h b/adaptors/devel-api/adaptor-framework/tilt-sensor.h
new file mode 100644 (file)
index 0000000..7ea0ede
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef __DALI_TILT_SENSOR_H__
+#define __DALI_TILT_SENSOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class TiltSensor;
+}
+}
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ * The basic usage is shown below:
+ *
+ * @code
+ *
+ *  void Example()
+ *  {
+ *    TiltSensor sensor = TiltSensor::Get();
+ *
+ *    // Try to enable the sensor
+ *    if ( sensor.Enable() )
+ *    {
+ *      // Query the current values
+ *      std::cout << "Roll = " << sensor.GetRoll() << ", Pitch = " << sensor.GetPitch() << std::endl;
+ *
+ *      // Get notifications when the device is tilted
+ *      sensor.SignalTilted().Connect( &OnTilted );
+ *    }
+ *  }
+ *
+ *  void OnTilted()
+ *  {
+ *    // Query the new values
+ *    std::cout << "Roll = " << sensor.GetRoll() << ", Pitch = " << sensor.GetPitch() << std::endl;
+ *  }
+ *
+ * @endcode
+ *
+ * While the tilt sensor is enabled, it will periodically poll for the latest pitch & roll values.
+ * For performance & power-saving, applications should disable this polling when no longer needed:
+ *
+ * @code
+ *
+ *  void EndExample()
+ *  {
+ *    // Disable the sensor when no longer needed
+ *    TiltSensor::Get().Disable();
+ *  }
+ *
+ * @endcode
+ */
+class DALI_IMPORT_API TiltSensor : public BaseHandle
+{
+public:
+
+  typedef Signal< void (const TiltSensor&) > TiltedSignalType;
+
+  static const float DEFAULT_UPDATE_FREQUENCY; // 60 hertz
+
+  /**
+   * Create an uninitialized handle.
+   * This can be initialized by calling TiltSensor::Get().
+   */
+  TiltSensor();
+
+  /**
+   * Create an initialized handle to the TiltSensor.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static TiltSensor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TiltSensor();
+
+  /**
+   * Attempt to enable the tilt-sensor. This will fail if the underlying sensor hardware is powered-down,
+   * typically this occurs when the device is set to "sleep" mode.
+   * @return True if the tilt-sensor is enabled.
+   */
+  bool Enable();
+
+  /**
+   * Disable the tilt-sensor.
+   */
+  void Disable();
+
+  /**
+   * Query whether the tilt-sensor is disabled.
+   * The sensor may be disabled automatically; typically this occurs when the device is set to "sleep" mode.
+   * @return True if the tilt-sensor is enabled.
+   */
+  bool IsEnabled() const;
+
+  /**
+   * Query the roll value. This is in the range -1 to 1.
+   * When the device is lying face-up on a flat surface, this method will return a value close to zero.
+   * A value close to 1 indicates that the right-side of the device is pointing upwards.
+   * A value close to -1 indicates that the right-side of the device is pointing downwards.
+   * @pre The tilt-sensor is enabled.
+   * @return The roll value.
+   */
+  float GetRoll() const;
+
+  /**
+   * Query the pitch value. This is in the range -1 to 1.
+   * When the device is lying face-up on a flat surface, this method will return a value close to zero.
+   * A value close to 1 indicates that the top of the device is pointing upwards.
+   * A value close to -1 indicates that the top of the device is pointing downwards.
+   * @pre The tilt-sensor is enabled.
+   * @return The pitch value.
+   */
+  float GetPitch() const;
+
+  /**
+   * Retrieve the rotation of the device.
+   * When the device is lying face-up on a flat surface, the rotation angle will be approximately zero.
+   * The roll & pitch of the device is considered to be a rotation around the Y and X axes respectively.
+   * @pre The tilt-sensor is enabled.
+   * @return The rotation in quaternion format.
+   */
+  Quaternion GetRotation() const;
+
+  /**
+   * This signal will be emitted when the device is tilted, if the tilt-sensor is enabled.
+   * The frequency of the signals can be controlled using SetUpdateFrequency().
+   * @return The signal to connect to.
+   *
+   * @note The signal name is "tilted" if using BaseHandle::ConnectSignal()
+   */
+  TiltedSignalType& TiltedSignal();
+
+  /**
+   * Set the sensor update frequency.
+   * The default is TiltSensor::DEFAULT_UPDATE_FREQUENCY.
+   * @param[in] frequencyHertz The frequency in hertz.
+   */
+  void SetUpdateFrequency( float frequencyHertz );
+
+  /**
+   * Query the sensor update frequency.
+   * @return The frequency in hertz.
+   */
+  float GetUpdateFrequency() const;
+
+  /**
+   * Set the threshold value for rotation in Radians, above which TiltedSignal should be emitted.
+   * The default is 0.0f in Radians (i.e) it will be emitted always at the frequency set.
+   * Example tiltSensor.SetRotationThreshold( Radian(Degree(10) ) // A rotation threshold of 10 degrees
+   * @param[in] rotationThreshold The threshold value for rotation.
+   */
+  void SetRotationThreshold( Radian rotationThreshold );
+
+  /**
+   * Query the rotation threshold above which TiltedSignal will be emitted.
+   * @return The rotation degree threshold in Radians.
+   */
+  Radian GetRotationThreshold() const;
+
+public: // Not intended for application developers
+
+  /**
+   * This constructor is used by TiltSensor::Get().
+   * @param[in] sensor A pointer to the tilt sensor.
+   */
+  explicit DALI_INTERNAL TiltSensor( Internal::Adaptor::TiltSensor* sensor );
+};
+
+} // namespace Dali
+
+#endif // __DALI_TILT_SENSOR_H__
diff --git a/adaptors/devel-api/adaptor-framework/virtual-keyboard.cpp b/adaptors/devel-api/adaptor-framework/virtual-keyboard.cpp
new file mode 100644 (file)
index 0000000..50fa03e
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <virtual-keyboard.h>
+
+// INTERNAL INCLUDES
+#include <virtual-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace VirtualKeyboard
+{
+
+void Show()
+{
+  Internal::Adaptor::VirtualKeyboard::Show();
+}
+
+void Hide()
+{
+  Internal::Adaptor::VirtualKeyboard::Hide();
+}
+
+bool IsVisible()
+{
+  return Internal::Adaptor::VirtualKeyboard::IsVisible();
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+  Internal::Adaptor::VirtualKeyboard::ApplySettings( settingsMap );
+}
+
+void SetReturnKeyType( const InputMethod::ActionButton type )
+{
+  Internal::Adaptor::VirtualKeyboard::SetReturnKeyType( type );
+}
+
+InputMethod::ActionButton  GetReturnKeyType()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetReturnKeyType();
+}
+
+void EnablePrediction(const bool enable)
+{
+  Internal::Adaptor::VirtualKeyboard::EnablePrediction(enable);
+}
+
+bool IsPredictionEnabled()
+{
+  return Internal::Adaptor::VirtualKeyboard::IsPredictionEnabled();
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetSizeAndPosition();
+}
+
+void RotateTo(int angle)
+{
+  Internal::Adaptor::VirtualKeyboard::RotateTo(angle);
+}
+
+StatusSignalType& StatusChangedSignal()
+{
+  return Internal::Adaptor::VirtualKeyboard::StatusChangedSignal();
+}
+
+VoidSignalType& ResizedSignal()
+{
+  return Internal::Adaptor::VirtualKeyboard::ResizedSignal();
+}
+
+VoidSignalType& LanguageChangedSignal()
+{
+  return Internal::Adaptor::VirtualKeyboard::LanguageChangedSignal();
+}
+
+TextDirection GetTextDirection()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetTextDirection();
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Dali
diff --git a/adaptors/devel-api/adaptor-framework/virtual-keyboard.h b/adaptors/devel-api/adaptor-framework/virtual-keyboard.h
new file mode 100644 (file)
index 0000000..f0e0a94
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef __DALI_VIRTUAL_KEYBOARD_H__
+#define __DALI_VIRTUAL_KEYBOARD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/math/rect.h>
+
+// INTERNAL INCLUDES
+#ifdef DALI_ADAPTOR_COMPILATION  // full path doesn't exist until adaptor is installed so we have to use relative
+// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
+#include "input-method.h"
+#else
+#include <dali/public-api/adaptor-framework/input-method.h>
+#endif
+
+namespace Dali
+{
+
+/**
+ * @brief This namespace is provided for application developers to be able to show and hide the on-screen keyboard.
+ *
+ * Key events are sent to the actor in focus. Focus is set through the actor Public API.
+ */
+namespace VirtualKeyboard
+{
+
+// Types
+
+typedef Signal< void () > VoidSignalType;
+typedef Signal< void (bool) > StatusSignalType;
+
+// Enumerations
+
+/**
+ * @brief The direction of text.
+ */
+enum TextDirection
+{
+  LeftToRight,
+  RightToLeft,
+};
+
+/**
+ * @brief The meaning of the return key.
+ */
+enum ReturnKeyType
+{
+  DEFAULT,
+  DONE,
+  GO,
+  JOIN,
+  LOGIN,
+  NEXT,
+  SEARCH,
+  SEND,
+  SIGNIN
+};
+
+// Functions
+/**
+ * @brief Show the virtual keyboard.
+ */
+DALI_IMPORT_API void Show();
+
+/**
+ * @brief Hide the virtual keyboard.
+ */
+DALI_IMPORT_API void Hide();
+
+/**
+ * @brief Returns whether the virtual keyboard is visible or not.
+ * @return true if visible, false otherwise.
+ */
+DALI_IMPORT_API bool IsVisible();
+
+/**
+ * @brief Set one or more of the Input Method Settings
+ * @param[in] settingsMap Map of Settings to be applied.
+ */
+DALI_IMPORT_API void ApplySettings( const Property::Map& settingsMap );
+
+/**
+ * @brief Set the specific return key into the virtual keyboard.
+ * @param[in] type the kind of return key types.
+ */
+DALI_IMPORT_API void SetReturnKeyType( const InputMethod::ActionButton type );
+
+/**
+ * @brief Retrieve the current return key type.
+ * @return the type of retun key.
+ */
+DALI_IMPORT_API InputMethod::ActionButton GetReturnKeyType();
+
+/**
+ * @brief Enable/disable prediction (predictive text).
+ *
+ * By default prediction text is enabled.
+ * @param[in] enable true or false to enable or disable
+ * Prediction can not be changed while the keyboard is visible. It must be set in advance of showing keyboard.
+ */
+DALI_IMPORT_API void EnablePrediction(const bool enable);
+
+/**
+ * @brief Returns whether prediction is enabled in the virtual keyboard
+ * @return true if predictive text enabled, false otherwise.
+ */
+DALI_IMPORT_API bool IsPredictionEnabled();
+
+/**
+ * @brief Provides size and position of keyboard.
+ *
+ * Position is relative to whether keyboard is visible or not.
+ * If keyboard is not visible then position will be off the screen.
+ * If keyboard is not being shown when this method is called the keyboard is partially setup (IMFContext) to get
+ * the values then taken down.  So ideally GetSizeAndPosition() should be called after Show().
+ * @return rect which is keyboard panel x, y, width, height
+ */
+DALI_IMPORT_API Dali::Rect<int> GetSizeAndPosition();
+
+/**
+ * @brief Rotates the keyboard orientation to the given angle.
+ *
+ * A value of 0 indicates the portrait orientation.
+ * Other valid values are 90, 180, 270.
+ * @param angle the angle is in degrees.
+ */
+DALI_IMPORT_API void RotateTo(int angle);
+
+/**
+ * @brief Returns text direction of the keyboard's current input language.
+ * @return The direction of the text.
+ */
+DALI_IMPORT_API TextDirection GetTextDirection();
+
+/**
+ * @brief Connect to this signal to be notified when the virtual keyboard is shown or hidden.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName(bool keyboardShown);
+ * @endcode
+ * If the parameter keyboardShown is true, then the keyboard has just shown, if it is false, then it
+ * has just been hidden.
+ * @return The signal to connect to.
+ */
+DALI_IMPORT_API StatusSignalType& StatusChangedSignal();
+
+/**
+ * @brief Connect to this signal to be notified when the virtual keyboard is resized.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName();
+ * @endcode
+ * User can get changed size by using GetSizeAndPosition() in the callback
+ * @return The signal to connect to.
+ */
+DALI_IMPORT_API VoidSignalType& ResizedSignal();
+
+/**
+ * @brief Connect to this signal to be notified when the virtual keyboard's language is changed.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName();
+ * @endcode
+ * User can get the text direction of the language by calling GetTextDirection() in the callback.
+ * @return The signal to connect to.
+ */
+DALI_IMPORT_API VoidSignalType& LanguageChangedSignal();
+
+} // namespace VirtualKeyboard
+
+} // namespace Dali
+
+#endif // __DALI_VIRTUAL_KEYBOARD_H__
diff --git a/adaptors/devel-api/file.list b/adaptors/devel-api/file.list
new file mode 100644 (file)
index 0000000..77443c7
--- /dev/null
@@ -0,0 +1,46 @@
+devel_api_src_files = \
+  $(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/bitmap-loader.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/bitmap-saver.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/clipboard.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/clipboard-event-notifier.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/color-controller.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/drag-and-drop-detector.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/event-feeder.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/feedback-player.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/imf-manager.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/orientation.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/performance-logger.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/singleton-service.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/sound-player.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/style-monitor.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/tilt-sensor.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/lifecycle-controller.cpp \
+  $(adaptor_devel_api_dir)/adaptor-framework/virtual-keyboard.cpp
+
+
+devel_api_adaptor_framework_header_files = \
+  $(adaptor_devel_api_dir)/adaptor-framework/accessibility-adaptor.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/accessibility-action-handler.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/accessibility-gesture-handler.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/bitmap-loader.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/bitmap-saver.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/clipboard-event-notifier.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/clipboard.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/color-controller.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/drag-and-drop-detector.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/event-feeder.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/feedback-plugin.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/feedback-player.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/imf-manager.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/lifecycle-controller.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/orientation.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/performance-logger.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/render-surface.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/singleton-service.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/sound-player.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/style-monitor.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/tilt-sensor.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/virtual-keyboard.h \
+  $(adaptor_devel_api_dir)/adaptor-framework/physical-keyboard.h
diff --git a/adaptors/integration-api/adaptor.h b/adaptors/integration-api/adaptor.h
new file mode 100644 (file)
index 0000000..cc79c35
--- /dev/null
@@ -0,0 +1,359 @@
+#ifndef __DALI_INTEGRATION_ADAPTOR_H__
+#define __DALI_INTEGRATION_ADAPTOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/callback.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/common/view-mode.h>
+
+// INTERNAL INCLUDES
+
+
+#ifdef DALI_ADAPTOR_COMPILATION  // full path doesn't exist until adaptor is installed so we have to use relative
+// @todo Make dali-adaptor code folder structure mirror the folder structure installed to dali-env
+#include <window.h>
+#include <application-configuration.h>
+#else
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/adaptor-framework/application-configuration.h>
+#endif
+
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Adaptor;
+}
+}
+
+/**
+ * @brief An Adaptor object is used to initialize and control how Dali runs.
+ *
+ * It provides a lifecycle interface that allows the application
+ * writer to provide their own main loop and other platform related
+ * features.
+ *
+ * The Adaptor class provides a means for initialising the resources required by the Dali::Core.
+ *
+ * When dealing with platform events, the application writer MUST ensure that Dali is called in a
+ * thread-safe manner.
+ *
+ * As soon as the Adaptor class is created and started, the application writer can initialise their
+ * Dali::Actor objects straight away or as required by the main loop they intend to use (there is no
+ * need to wait for an initialise signal as per the Dali::Application class).
+ *
+ * The Adaptor does emit a Resize signal which informs the user when the surface is resized.
+ * Tizen and Linux Adaptors should follow the example below:
+ *
+ * @code
+ * void CreateProgram(DaliAdaptor& adaptor)
+ * {
+ *   // Create Dali components...
+ *   // Can instantiate adaptor here instead, if required
+ * }
+ *
+ * int main ()
+ * {
+ *   // Initialise platform
+ *   MyPlatform.Init();
+ *
+ *   // Create an 800 by 1280 window positioned at (0,0).
+ *   Dali::PositionSize positionSize(0, 0, 800, 1280);
+ *   Dali::Window window = Dali::Window::New( positionSize, "My Application" );
+ *
+ *   // Create an adaptor which uses that window for rendering
+ *   Dali::Adaptor adaptor = Dali::Adaptor::New( window );
+ *   adaptor.Start();
+ *
+ *   CreateProgram(adaptor);
+ *   // Or use this as a callback function depending on the platform initialisation sequence.
+ *
+ *   // Start Main Loop of your platform
+ *   MyPlatform.StartMainLoop();
+ *
+ *   return 0;
+ * }
+ * @endcode
+ *
+ * If required, you can also connect class member functions to a signal:
+ *
+ * @code
+ * MyApplication application;
+ * adaptor.ResizedSignal().Connect(&application, &MyApplication::Resize);
+ * @endcode
+ *
+ * @see RenderSurface
+ */
+class DALI_IMPORT_API Adaptor
+{
+public:
+
+  typedef Signal< void (Adaptor&) > AdaptorSignalType; ///< Generic Type for adaptor signals
+
+public:
+  /**
+   * @brief Create a new adaptor using the window.
+   *
+   * @param[in] window The window to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window );
+
+  /**
+   * @brief Create a new adaptor using the window.
+   *
+   * @param[in] window The window to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window, Configuration::ContextLoss configuration );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] nativeWindow native window handle
+   * @param[in] surface The surface to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Any nativeWindow, const Dali::RenderSurface& surface );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] nativeWindow native window handle
+   * @param[in] surface The surface to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Any nativeWindow, const Dali::RenderSurface& surface, Configuration::ContextLoss configuration = Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS);
+
+  /**
+   * @brief Virtual Destructor.
+   */
+  virtual ~Adaptor();
+
+public:
+
+  /**
+   * @brief Starts the Adaptor.
+   */
+  void Start();
+
+  /**
+   * @brief Pauses the Adaptor.
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes the Adaptor, if previously paused.
+   *
+   * @note If the adaptor is not paused, this does not do anything.
+   */
+  void Resume();
+
+  /**
+   * @brief Stops the Adaptor.
+   */
+  void Stop();
+
+  /**
+   * @brief Ensures that the function passed in is called from the main loop when it is idle.
+   * @note Function must be called from the main event thread only.
+   *
+   * A callback of the following type may be used:
+   * @code
+   *   void MyFunction();
+   * @endcode
+   *
+   * @param[in] callback The function to call.
+   * @return true if added successfully, false otherwise
+   *
+   * @note Ownership of the callback is passed onto this class.
+   */
+  bool AddIdle( CallbackBase* callback );
+
+  /**
+   * @brief Replaces the rendering surface
+   *
+   * @param[in] nativeWindow native window handle
+   * @param[in] surface to use
+   */
+  void ReplaceSurface( Any nativeWindow, Dali::RenderSurface& surface );
+
+  /**
+   * @brief Get the render surface the adaptor is using to render to.
+   *
+   * @return reference to current render surface
+   */
+  RenderSurface& GetSurface();
+
+  /**
+   * @brief Release any locks the surface may hold.
+   *
+   * For example, after compositing an offscreen surface, use this method to allow
+   * rendering to continue.
+   */
+  void ReleaseSurfaceLock();
+
+  /**
+   * @brief Set the number of frames per render.
+   *
+   * This enables an application to deliberately render with a reduced FPS.
+   * @param[in] numberOfVSyncsPerRender The number of vsyncs between successive renders.
+   * Suggest this is a power of two:
+   * 1 - render each vsync frame
+   * 2 - render every other vsync frame
+   * 4 - render every fourth vsync frame
+   * 8 - render every eighth vsync frame
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * @brief Set whether the frame count per render is managed using the hardware VSync or
+   * manually timed.
+   *
+   * @param[in] useHardware True if the hardware VSync should be used
+   */
+  void SetUseHardwareVSync(bool useHardware);
+
+  /**
+   * @brief Returns a reference to the instance of the adaptor used by the current thread.
+   *
+   * @return A reference to the adaptor.
+   * @pre The adaptor has been initialised.
+   * @note This is only valid in the main thread.
+   */
+  static Adaptor& Get();
+
+  /**
+   * @brief Checks whether the adaptor is available.
+   *
+   * @return true, if it is available, false otherwise.
+   */
+  static bool IsAvailable();
+
+  /**
+   * @brief Call this method to notify Dali when scene is created and initialized.
+   *
+   * Notify Adaptor that the scene has been created.
+   */
+  void NotifySceneCreated();
+
+  /**
+   * @brief Call this method to notify Dali when the system language changes.
+   *
+   * Use this only when NOT using Dali::Application, As Application created using
+   * Dali::Application will automatically receive notification of language change.
+   * When Dali::Application is not used, the application developer should
+   * use app-core to receive language change notifications and should update Dali
+   * by calling this method.
+   */
+  void NotifyLanguageChanged();
+
+  /**
+   * @brief Sets minimum distance in pixels that the fingers must move towards/away from each other in order to
+   * trigger a pinch gesture
+   *
+   * @param[in] distance The minimum pinch distance in pixels
+   */
+  void SetMinimumPinchDistance(float distance);
+
+  /**
+   * @brief Feed a touch point to the adaptor.
+   *
+   * @param[in] point touch point
+   * @param[in] timeStamp time value of event
+   */
+  void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+  /**
+   * @brief Feed a wheel event to the adaptor.
+   *
+   * @param[in]  wheelEvent wheel event
+   */
+  void FeedWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * @brief Feed a key event to the adaptor.
+   *
+   * @param[in] keyEvent The key event holding the key information.
+   */
+  void FeedKeyEvent( KeyEvent& keyEvent );
+
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
+  /**
+   * @copydoc Dali::Application::SetViewMode();
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::Application::SetStereoBase();
+   */
+  void SetStereoBase( float stereoBase );
+
+public:  // Signals
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any
+   * special activities when the surface Dali is being rendered on is resized.
+   *
+   * @return The signal to connect to
+   */
+  AdaptorSignalType& ResizedSignal();
+
+  /**
+   * @brief This signal is emitted when the language is changed on the device.
+   *
+   * @return The signal to connect to
+   */
+  AdaptorSignalType& LanguageChangedSignal();
+
+private:
+
+  // Undefined
+  Adaptor(const Adaptor&);
+  Adaptor& operator=(Adaptor&);
+
+private:
+
+  /**
+   * @brief Create an uninitialized Adaptor.
+   */
+  Adaptor();
+
+  Internal::Adaptor::Adaptor* mImpl; ///< Implementation object
+  friend class Internal::Adaptor::Adaptor;
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_ADAPTOR_H__
diff --git a/adaptors/integration-api/egl-interface.h b/adaptors/integration-api/egl-interface.h
new file mode 100644 (file)
index 0000000..3d02ef2
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __DALI_INTEGRATION_EGL_INTERFACE_H__
+#define __DALI_INTEGRATION_EGL_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+enum ColorDepth
+{
+  COLOR_DEPTH_24 = 24,
+  COLOR_DEPTH_32 = 32
+};
+
+/**
+ * EglInterface provides an interface for managing EGL contexts
+ */
+class EglInterface
+{
+public:
+  /**
+    * Create the OpenGL context.
+    * @return true if successful
+    */
+  virtual bool CreateContext() = 0;
+
+  /**
+   * Make the OpenGL context current
+   */
+  virtual void MakeContextCurrent() = 0;
+
+  /**
+   * Terminate GL
+   */
+  virtual void TerminateGles() = 0;
+
+  /**
+   * Performs an OpenGL swap buffers command
+   */
+  virtual void SwapBuffers() = 0;
+
+  /**
+   * Performs an OpenGL copy buffers command
+   */
+  virtual void CopyBuffers() = 0;
+
+  /**
+   * Performs an EGL wait GL command
+   */
+  virtual void WaitGL() = 0;
+
+  /**
+   * Query whether an pixmap image is y-inverted
+   * @return true if a pixmap is y-inverted, otherwise false
+   */
+  virtual bool IsPixmapYInverted() = 0;
+
+protected:
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~EglInterface() {}
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_EGL_INTERFACE_H__
diff --git a/adaptors/integration-api/file.list b/adaptors/integration-api/file.list
new file mode 100644 (file)
index 0000000..2779d84
--- /dev/null
@@ -0,0 +1,18 @@
+adaptor_integration_api_header_files = \
+  $(adaptor_integration_api_dir)/adaptor.h \
+  $(adaptor_integration_api_dir)/egl-interface.h \
+  $(adaptor_integration_api_dir)/thread-synchronization-interface.h \
+  $(adaptor_integration_api_dir)/trigger-event-interface.h \
+  $(adaptor_integration_api_dir)/trigger-event-factory-interface.h \
+  $(adaptor_integration_api_dir)/trigger-event-factory.h \
+  $(adaptor_integration_api_dir)/pixmap-render-surface-factory.h
+
+adaptor_integration_wayland_api_header_files = \
+  $(adaptor_integration_api_dir)/wayland/ecore-wl-types.h \
+  $(adaptor_integration_api_dir)/wayland/ecore-wl-render-surface.h \
+  $(adaptor_integration_api_dir)/wayland/pixmap-render-surface.h
+
+adaptor_integration_x11_api_header_files = \
+  $(adaptor_integration_api_dir)/x11/ecore-x-types.h \
+  $(adaptor_integration_api_dir)/x11/ecore-x-render-surface.h \
+  $(adaptor_integration_api_dir)/x11/pixmap-render-surface.h
diff --git a/adaptors/integration-api/pixmap-render-surface-factory.h b/adaptors/integration-api/pixmap-render-surface-factory.h
new file mode 100644 (file)
index 0000000..971dc35
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __DALI_INTEGRATION_PIXMAP_RENDER_SURFACE_FACTORY_H__
+#define __DALI_INTEGRATION_PIXMAP_RENDER_SURFACE_FACTORY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+class PixmapRenderSurface;
+
+/**
+ * Surface factory function for pixmap
+ * A pixmap surface is created.
+ *
+ * @param [in] positionSize the position and size of the surface to create
+ * @param [in] surface X Pixmap to use, or null for default.
+ * @param [in] name Name of surface passed in
+ * @param [in] isTransparent Whether the surface has an alpha channel
+ */
+PixmapRenderSurface* CreatePixmapSurface(PositionSize       positionSize,
+                                         Any                surface,
+                                         const std::string& name,
+                                         bool               isTransparent);
+
+} // namespace ECoreX
+
+} // namespace Dali
+
+#endif //  __DALI_INTEGRATION_PIXMAP_RENDER_SURFACE_FACTORY_H__
diff --git a/adaptors/integration-api/thread-synchronization-interface.h b/adaptors/integration-api/thread-synchronization-interface.h
new file mode 100644 (file)
index 0000000..15164be
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__
+#define __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+namespace Dali
+{
+
+/**
+ * @brief Interface for the ThreadSyncrhonization handler.
+ *
+ * This handler ensure the threads are synchronized properly.
+ */
+class ThreadSynchronizationInterface
+{
+public:
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Event Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @brief Surface informs that the post-render has been completed.
+   *
+   * @note Should only be called by the Event Thread if post-rendering is required.
+   */
+  virtual void PostRenderComplete() = 0;
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Render Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @brief Called just before the post rendering is done by the surface.
+   *
+   * @note Should only be called by the Render Thread if post-rendering is required.
+   */
+  virtual void PostRenderStarted() = 0;
+
+  /**
+   * @brief Blocks the render thread until the post rendering has been completed by the surface.
+   *
+   * @note Should only be called by the Render Thread if post-rendering is required.
+   */
+  virtual void PostRenderWaitForCompletion() = 0;
+
+protected:
+
+  /**
+   * @brief Protected constructor, no creation through this interface
+   */
+  ThreadSynchronizationInterface( ) { }
+
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~ThreadSynchronizationInterface() { }
+
+private:
+
+  // Undefined copy constructor.
+  ThreadSynchronizationInterface( const ThreadSynchronizationInterface& );
+
+  // Undefined assignment operator.
+  ThreadSynchronizationInterface& operator=( const ThreadSynchronizationInterface& );
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H__
diff --git a/adaptors/integration-api/trigger-event-factory-interface.h b/adaptors/integration-api/trigger-event-factory-interface.h
new file mode 100644 (file)
index 0000000..947f812
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_INTERFACE_H__
+#define __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <trigger-event-interface.h>
+
+namespace Dali
+{
+
+/**
+ * @brief Trigger interface factory class for creating a TriggerEvents
+ *
+ */
+class TriggerEventFactoryInterface
+{
+public:
+
+
+  /**
+   * @brief Create a new concrete implementation of the event trigger interface.
+   * @param callback called when interface->Trigger() is called
+   * @param options TriggerEventInterface option
+   * @return pointer to a new trigger event
+   * @note Ownership of callback should be taken over by deriving classes
+   */
+  virtual TriggerEventInterface* CreateTriggerEvent( CallbackBase* callback,
+                                                     TriggerEventInterface::Options options ) = 0;
+  /**
+   * @brief destroy a trigger event
+   * @param triggerEventInterface event to destroy
+   */
+  virtual void DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface ) = 0;
+
+protected:
+
+  /**
+   * @brief  Constructor
+   */
+  TriggerEventFactoryInterface()
+  {
+  }
+
+  /**
+   * @brief Virtual Destructor
+   */
+  virtual ~TriggerEventFactoryInterface()
+  {
+  }
+
+private:
+
+
+  // Undefined copy constructor.
+  TriggerEventFactoryInterface( const TriggerEventFactoryInterface& );
+
+  // Undefined assignment operator.
+  TriggerEventFactoryInterface& operator=( const TriggerEventFactoryInterface& );
+
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_INTERFACE_H__
diff --git a/adaptors/integration-api/trigger-event-factory.h b/adaptors/integration-api/trigger-event-factory.h
new file mode 100644 (file)
index 0000000..1633a0d
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H__
+#define __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <trigger-event-factory-interface.h>
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+/**
+ * @brief Trigger interface factory class
+ *
+ */
+class DALI_IMPORT_API TriggerEventFactory : public TriggerEventFactoryInterface
+{
+
+public:
+
+  /**
+   * @brief Constructor
+   */
+  TriggerEventFactory()
+  {
+  }
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~TriggerEventFactory()
+  {
+  }
+
+  /**
+   * @copydoc TriggerEventFactoryInterface::CreateTriggerEvent
+   */
+  virtual TriggerEventInterface* CreateTriggerEvent(  CallbackBase* callback, TriggerEventInterface::Options options );
+
+
+  /**
+   * @copydoc TriggerEventFactoryInterface::DestroyTriggerEvent
+   */
+  virtual void DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface );
+
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H__
diff --git a/adaptors/integration-api/trigger-event-interface.h b/adaptors/integration-api/trigger-event-interface.h
new file mode 100644 (file)
index 0000000..c6c1eaa
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H__
+#define __DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+namespace Dali
+{
+
+/**
+ * @brief Interface for a trigger event class.
+ *
+ * The trigger event is a way of running a function call back on the main event thread of Dali.
+ * To create a trigger event use the factory interface.
+ */
+class TriggerEventInterface
+{
+
+public:
+
+  /**
+   * @brief trigger event options
+   */
+  enum Options
+  {
+    KEEP_ALIVE_AFTER_TRIGGER,
+    DELETE_AFTER_TRIGGER,  // automatically delete the trigger event object, after Trigger() is called.
+  };
+
+  /**
+   * @brief Triggers the event.
+   * This method cannot ever block, it needs to return immediately.
+   * This can be called from one thread in order to wake up another thread.
+   */
+  virtual void Trigger() = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  TriggerEventInterface( )
+  {
+  }
+
+public:
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~TriggerEventInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  TriggerEventInterface( const TriggerEventInterface& );
+
+  // Undefined assignment operator.
+  TriggerEventInterface& operator=( const TriggerEventInterface& );
+
+
+};
+
+} // namespace Dali
+
+#endif // __DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H__
diff --git a/adaptors/integration-api/wayland/ecore-wl-render-surface.h b/adaptors/integration-api/wayland/ecore-wl-render-surface.h
new file mode 100644 (file)
index 0000000..99ceb45
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef __DALI_ECORE_WL_RENDER_SURFACE_H__
+#define __DALI_ECORE_WL_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_Wayland.h>
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <render-surface.h>
+#include <egl-interface.h>
+
+namespace Dali
+{
+
+class TriggerEventInterface;
+
+namespace ECore
+{
+
+/**
+ * Ecore Wayland implementation of render surface.
+ * @todo change namespace to ECore_Wayland as the class
+ * is no longer pure Wayland.
+ */
+class DALI_IMPORT_API EcoreWlRenderSurface : public Dali::RenderSurface
+{
+public:
+  /**
+    * Uses an Wayland surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a X-window or X-pixmap (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  EcoreWlRenderSurface(Dali::PositionSize positionSize,
+                       Any surface,
+                       const std::string& name,
+                       bool isTransparent = false);
+
+  /**
+   * Destructor.
+   * Will delete the display, if it has ownership.
+   * Will delete the window/pixmap if it has owner ship
+   */
+  virtual ~EcoreWlRenderSurface();
+
+protected:
+  /**
+   * Second stage construction
+   * Creates the surface (window, pixmap or native buffer)
+   */
+  void Init( Any surface );
+
+public: // API
+
+  /**
+   * @brief Sets the render notification trigger to call when render thread is completed a frame
+   *
+   * @param renderNotification to use
+   */
+  void SetRenderNotification(TriggerEventInterface* renderNotification);
+
+  /**
+   * @brief Get window handle
+   *
+   * @return the Ecore X window handle
+   */
+  Ecore_Wl_Window* GetWlWindow();
+
+  /**
+   * Get the surface as an Ecore_Wl_Window
+   */
+  virtual Ecore_Wl_Window* GetDrawable();
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::GetPositionSize()
+   */
+  virtual PositionSize GetPositionSize() const;
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize);
+
+  /**
+   * @copydoc Dali::RenderSurface::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender() = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::ReleaseLock()
+   */
+  virtual void ReleaseLock() = 0;
+
+private:
+
+  /**
+   * Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+protected:
+
+  /**
+   * Create XRenderable
+   */
+  virtual void CreateWlRenderable() = 0;
+
+  /**
+   * Use an existing render surface
+   * @param surfaceId the id of the surface
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId ) = 0;
+
+protected: // Data
+
+  PositionSize                mPosition;           ///< Position
+  std::string                 mTitle;              ///< Title of window which shows from "xinfo -topvwins" command
+  TriggerEventInterface*      mRenderNotification; ///< Render notification trigger
+  ColorDepth                  mColorDepth;         ///< Color depth of surface (32 bit or 24 bit)
+  bool                        mOwnSurface;         ///< Whether we own the surface (responsible for deleting it)
+};
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_ECORE_WL_RENDER_SURFACE_H__
diff --git a/adaptors/integration-api/wayland/ecore-wl-types.h b/adaptors/integration-api/wayland/ecore-wl-types.h
new file mode 100644 (file)
index 0000000..97869fb
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __DALI_WL_TYPES_H__
+#define __DALI_WL_TYPES_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <wayland-client.h>
+
+namespace Dali
+{
+
+typedef ::wl_display WlDisplay;
+typedef ::wl_surface WlSurface;
+
+} // namespace Dali
+
+#endif /* __DALI_WL_TYPES_H__ */
diff --git a/adaptors/integration-api/wayland/pixmap-render-surface.h b/adaptors/integration-api/wayland/pixmap-render-surface.h
new file mode 100644 (file)
index 0000000..190e1ae
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
+#define __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <ecore-wl-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+/**
+ * Ecore X11 implementation of render surface.
+ */
+class PixmapRenderSurface : public EcoreWlRenderSurface
+{
+public:
+
+  /**
+    * Uses an Wayland surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a Wayland-window (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  PixmapRenderSurface( Dali::PositionSize positionSize,
+                       Any surface,
+                       const std::string& name,
+                       bool isTransparent = false);
+
+  /**
+   * @copydoc Dali::RenderSurface::~RenderSurface
+   */
+  virtual ~PixmapRenderSurface();
+
+public: // API
+
+  /**
+   * @copydoc Dali::ECore::EcoreWlRenderSurface::GetDrawable()
+   */
+  virtual Ecore_Wl_Window* GetDrawable();
+
+  /**
+   * @brief GetSurface
+   *
+   * @return pixmap
+   */
+  virtual Any GetSurface();
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction );
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurface::StopRender()
+   */
+  virtual void StopRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+private:
+  enum SyncMode
+  {
+    SYNC_MODE_NONE,
+    SYNC_MODE_WAIT
+  };
+
+  /**
+   * Set the sync mode.
+   * @param[in] syncMode The sync mode
+   */
+  void SetSyncMode( SyncMode syncMode );
+
+  /**
+   * If sync mode is WAIT, then acquire a lock. This prevents render thread from
+   * continuing until the pixmap has been drawn by the compositor.
+   * It must be released for rendering to continue.
+   */
+  void AcquireLock();
+
+  /**
+   * Release any locks.
+   */
+  void ReleaseLock();
+
+  /**
+   * Create XPixmap
+   */
+  virtual void CreateWlRenderable();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::ECore::RenderSurface::UseExistingRenderable
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId );
+
+private: // Data
+
+};
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
diff --git a/adaptors/integration-api/x11/ecore-x-render-surface.h b/adaptors/integration-api/x11/ecore-x-render-surface.h
new file mode 100644 (file)
index 0000000..7aed8b5
--- /dev/null
@@ -0,0 +1,192 @@
+#ifndef __DALI_ECORE_X_RENDER_SURFACE_H__
+#define __DALI_ECORE_X_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_X.h>
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <render-surface.h>
+#include <ecore-x-types.h>
+#include <egl-interface.h>
+
+namespace Dali
+{
+
+class TriggerEventInterface;
+
+namespace ECore
+{
+
+/**
+ * Ecore X11 implementation of render surface.
+ * @todo change namespace to ECore_X11 as the class
+ * is no longer pure X11.
+ */
+class DALI_IMPORT_API EcoreXRenderSurface : public Dali::RenderSurface
+{
+public:
+  /**
+    * Uses an X11 surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a X-window or X-pixmap (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  EcoreXRenderSurface(Dali::PositionSize positionSize,
+                      Any surface,
+                      const std::string& name,
+                      bool isTransparent = false);
+
+  /**
+   * Destructor.
+   * Will delete the display, if it has ownership.
+   * Will delete the window/pixmap if it has owner ship
+   */
+  virtual ~EcoreXRenderSurface();
+
+protected:
+  /**
+   * Second stage construction
+   * Creates the surface (window, pixmap or native buffer)
+   */
+  void Init( Any surface );
+
+public: // API
+
+  /**
+   * @brief Sets the render notification trigger to call when render thread is completed a frame
+   *
+   * @param renderNotification to use
+   */
+  void SetRenderNotification(TriggerEventInterface* renderNotification);
+
+  /**
+   * @brief Get window handle
+   *
+   * @return the Ecore X window handle
+   */
+  Ecore_X_Window GetXWindow();
+
+  /**
+   * Get the surface as an Ecore_X_drawable
+   */
+  virtual Ecore_X_Drawable GetDrawable();
+
+  /**
+   * @brief Get the render surface the adaptor is using to render to.
+   *
+   * @return reference to current render surface (eg, pixmap / window)
+   */
+  virtual Any GetSurface() = 0;
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::GetPositionSize()
+   */
+  virtual PositionSize GetPositionSize() const;
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize);
+
+  /**
+   * @copydoc Dali::RenderSurface::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender() = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurface::ReleaseLock()
+   */
+  virtual void ReleaseLock() = 0;
+
+private:
+
+  /**
+   * Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+protected:
+
+  /**
+   * Create XRenderable
+   */
+  virtual void CreateXRenderable() = 0;
+
+  /**
+   * Use an existing render surface
+   * @param surfaceId the id of the surface
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId ) = 0;
+
+protected: // Data
+
+  PositionSize                mPosition;           ///< Position
+  std::string                 mTitle;              ///< Title of window which shows from "xinfo -topvwins" command
+  TriggerEventInterface*      mRenderNotification; ///< Render notification trigger
+  ColorDepth                  mColorDepth;         ///< Color depth of surface (32 bit or 24 bit)
+  bool                        mOwnSurface;         ///< Whether we own the surface (responsible for deleting it)
+};
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_ECORE_X_RENDER_SURFACE_H__
diff --git a/adaptors/integration-api/x11/ecore-x-types.h b/adaptors/integration-api/x11/ecore-x-types.h
new file mode 100644 (file)
index 0000000..f425033
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef __DALI_X11_TYPES_H__
+#define __DALI_X11_TYPES_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <X11/Xlib.h>
+
+namespace Dali
+{
+
+typedef ::Pixmap XPixmap;
+typedef ::Window XWindow;
+typedef ::Display XDisplay;
+typedef ::Screen XScreen;
+
+} // namespace Dali
+
+#endif /* __DALI_X11_TYPES_H__ */
diff --git a/adaptors/integration-api/x11/pixmap-render-surface.h b/adaptors/integration-api/x11/pixmap-render-surface.h
new file mode 100644 (file)
index 0000000..471462f
--- /dev/null
@@ -0,0 +1,142 @@
+#ifndef __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
+#define __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <ecore-x-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+/**
+ * Ecore X11 implementation of render surface.
+ */
+class PixmapRenderSurface : public EcoreXRenderSurface
+{
+public:
+
+  /**
+    * Uses an X11 surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a X-window or X-pixmap (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  PixmapRenderSurface( Dali::PositionSize positionSize,
+                       Any surface,
+                       const std::string& name,
+                       bool isTransparent = false);
+
+  /**
+   * @copydoc Dali::RenderSurface::~RenderSurface
+   */
+  virtual ~PixmapRenderSurface();
+
+public: // API
+
+  /**
+   * @copydoc Dali::ECore::EcoreXRenderSurface::GetDrawable()
+   */
+  virtual Ecore_X_Drawable GetDrawable();
+
+  /**
+   * @brief GetSurface
+   *
+   * @return pixmap
+   */
+  virtual Any GetSurface();
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction );
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurface::StopRender()
+   */
+  virtual void StopRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+private:
+
+  /**
+   * Release any locks.
+   */
+  void ReleaseLock();
+
+  /**
+   * Create XPixmap
+   */
+  virtual void CreateXRenderable();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::ECore::RenderSurface::UseExistingRenderable
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId );
+
+private: // Data
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H__
diff --git a/adaptors/mobile/file.list b/adaptors/mobile/file.list
new file mode 100644 (file)
index 0000000..a38ad4b
--- /dev/null
@@ -0,0 +1,5 @@
+# mobile profile internal files
+adaptor_common_internal_mobile_profile_src_files = \
+  $(adaptor_mobile_dir)/pixmap-render-surface-factory.cpp \
+  $(adaptor_mobile_dir)/mobile-system-settings.cpp \
+  $(adaptor_mobile_dir)/mobile-color-controller-impl.cpp
diff --git a/adaptors/mobile/mobile-color-controller-impl.cpp b/adaptors/mobile/mobile-color-controller-impl.cpp
new file mode 100644 (file)
index 0000000..732d459
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <common/color-controller-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return ColorController::Get();
+}
+Dali::TypeRegistration COLOR_CONTROLLER_TYPE( typeid(Dali::ColorController), typeid(Dali::BaseHandle), Create );
+
+}
+
+Dali::ColorController ColorController::Get()
+{
+  Dali::ColorController colorController;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ColorController ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      colorController = Dali::ColorController( dynamic_cast< ColorController* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      colorController = Dali::ColorController( new ColorController( ) );
+      service.Register( typeid( colorController ), colorController );
+    }
+  }
+
+  return colorController;
+
+}
+
+ColorController::ColorController()
+{
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return false;
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/mobile/mobile-system-settings.cpp b/adaptors/mobile/mobile-system-settings.cpp
new file mode 100644 (file)
index 0000000..446078f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <system_settings.h>
+#include <Elementary.h>
+
+// INTERNAL INCLUDES
+#include <system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/mobile/pixmap-render-surface-factory.cpp b/adaptors/mobile/pixmap-render-surface-factory.cpp
new file mode 100644 (file)
index 0000000..9517ba8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <pixmap-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+DALI_EXPORT_API PixmapRenderSurface* CreatePixmapSurface(
+                                     PositionSize       positionSize,
+                                     Any                surface,
+                                     const std::string& name,
+                                     bool               isTransparent)
+{
+  return new PixmapRenderSurface(positionSize, surface, name, isTransparent);
+}
+
+} // namespace ECoreX
+
+} // namespace Dali
+
+
+
diff --git a/adaptors/public-api/adaptor-framework/application-configuration.h b/adaptors/public-api/adaptor-framework/application-configuration.h
new file mode 100644 (file)
index 0000000..fbcc0bd
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __DALI_APPLICATION_CONFIGURATION_H__
+#define __DALI_APPLICATION_CONFIGURATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Application configuration enumerations
+ * @since_tizen 2.4
+ */
+namespace Configuration
+{
+
+/**
+ * @brief Enumeration about application context loss policy
+ * @since_tizen 2.4
+ */
+enum ContextLoss
+{
+  APPLICATION_HANDLES_CONTEXT_LOSS,  ///< Application will tear down and recreate UI on context loss and context regained signals. Dali doesn't need to retain data.
+  APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS, ///< Application expects Dali to retain data ( increased memory footprint )
+};
+
+} // Configuration
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif
diff --git a/adaptors/public-api/adaptor-framework/application.cpp b/adaptors/public-api/adaptor-framework/application.cpp
new file mode 100644 (file)
index 0000000..fac96f1
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "application.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <application-impl.h>
+
+namespace Dali
+{
+
+Application Application::New()
+{
+  return New( NULL, NULL );
+}
+
+Application Application::New( int* argc, char **argv[] )
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, "", OPAQUE );
+  return Application(internal.Get());
+}
+
+Application Application::New( int* argc, char **argv[], const std::string& stylesheet )
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, OPAQUE );
+  return Application(internal.Get());
+}
+
+Application Application::New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode )
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode );
+  return Application(internal.Get());
+}
+
+Application::~Application()
+{
+}
+
+Application::Application()
+{
+}
+
+Application::Application(const Application& application)
+: BaseHandle(application)
+{
+}
+
+Application& Application::operator=(const Application& application)
+{
+  if( *this != application )
+  {
+    BaseHandle::operator=( application );
+  }
+  return *this;
+}
+
+void Application::MainLoop()
+{
+  Internal::Adaptor::GetImplementation(*this).MainLoop(Configuration::APPLICATION_HANDLES_CONTEXT_LOSS);
+}
+
+void Application::MainLoop(Configuration::ContextLoss configuration)
+{
+  Internal::Adaptor::GetImplementation(*this).MainLoop(configuration);
+}
+
+void Application::Lower()
+{
+  Internal::Adaptor::GetImplementation(*this).Lower();
+}
+
+void Application::Quit()
+{
+  Internal::Adaptor::GetImplementation(*this).Quit();
+}
+
+bool Application::AddIdle( CallbackBase* callback )
+{
+  return Internal::Adaptor::GetImplementation(*this).AddIdle( callback );
+}
+
+Window Application::GetWindow()
+{
+  return Internal::Adaptor::GetImplementation(*this).GetWindow();
+}
+
+void Application::ReplaceWindow(PositionSize windowPosition, const std::string& name)
+{
+  Internal::Adaptor::GetImplementation(*this).ReplaceWindow(windowPosition, name);
+}
+
+void Application::SetViewMode( ViewMode viewMode )
+{
+  Internal::Adaptor::GetImplementation(*this).SetViewMode( viewMode );
+}
+
+ViewMode Application::GetViewMode() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetViewMode();
+}
+
+void Application::SetStereoBase( float stereoBase )
+{
+  Internal::Adaptor::GetImplementation(*this).SetStereoBase( stereoBase );
+}
+
+float Application::GetStereoBase() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetStereoBase();
+}
+
+Application::AppSignalType& Application::InitSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).InitSignal();
+}
+
+Application::AppSignalType& Application::TerminateSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TerminateSignal();
+}
+
+Application::AppSignalType& Application::PauseSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).PauseSignal();
+}
+
+Application::AppSignalType& Application::ResumeSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResumeSignal();
+}
+
+Application::AppSignalType& Application::ResetSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResetSignal();
+}
+
+Application::AppSignalType& Application::ResizeSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResizeSignal();
+}
+
+Application::AppControlSignalType & Application::AppControlSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).AppControlSignal();
+}
+
+Application::AppSignalType& Application::LanguageChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).LanguageChangedSignal();
+}
+
+Application::AppSignalType& Application::RegionChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).RegionChangedSignal();
+}
+
+Application::AppSignalType& Application::BatteryLowSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).BatteryLowSignal();
+}
+
+Application::AppSignalType& Application::MemoryLowSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).MemoryLowSignal();
+}
+
+Application::Application(Internal::Adaptor::Application* application)
+: BaseHandle(application)
+{
+}
+
+
+} // namespace Dali
diff --git a/adaptors/public-api/adaptor-framework/application.h b/adaptors/public-api/adaptor-framework/application.h
new file mode 100644 (file)
index 0000000..8efc3a9
--- /dev/null
@@ -0,0 +1,369 @@
+#ifndef __DALI_APPLICATION_H__
+#define __DALI_APPLICATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/view-mode.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/callback.h>
+
+
+// INTERNAL INCLUDES
+#include "application-configuration.h"
+#include "window.h"
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Application;
+}
+}
+/**
+ * @brief An Application class object should be created by every application
+ * that wishes to use Dali.  It provides a means for initialising the
+ * resources required by the Dali::Core.
+ *
+ * The Application class emits several signals which the user can
+ * connect to.  The user should not create any Dali objects in the main
+ * function and instead should connect to the Init signal of the
+ * Application and create the Dali objects in the connected callback.
+ *
+ * Applications should follow the example below:
+ *
+ * @code
+ * void CreateProgram(Application app)
+ * {
+ *   // Create Dali components...
+ *   // Can instantiate here, if required
+ * }
+ *
+ * int main (int argc, char **argv)
+ * {
+ *   Application app = Application::New(&argc, &argv);
+ *   app.InitSignal().Connect(&CreateProgram);
+ *   app.MainLoop();
+ * }
+ * @endcode
+ *
+ * If required, you can also connect class member functions to a signal:
+ *
+ * @code
+ * MyApplication app;
+ * app.ResumeSignal().Connect(&app, &MyApplication::Resume);
+ * @endcode
+ *
+ * This class accepts command line arguments as well. The following options are supported:
+ *
+ * @code
+ *     --no-vsync       Disable VSync on Render
+ *  -w|--width          Stage Width
+ *  -h|--height         Stage Height
+ *  -d|--dpi            Emulated DPI
+ *     --help           Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
+ * @since_tizen 2.4
+ */
+class DALI_IMPORT_API Application : public BaseHandle
+{
+public:
+
+  typedef Signal< void (Application&) > AppSignalType;
+  typedef Signal< void (Application&, void *) > AppControlSignalType;
+
+  /**
+   * @brief Decides whether a Dali application window is opaque or transparent.
+   * @since_tizen 2.4
+   */
+  enum WINDOW_MODE
+  {
+    OPAQUE = 0,       ///< The window will be opaque
+    TRANSPARENT = 1   ///< The window transparency will match the alpha value set in Dali::Stage::SetBackgroundcolor()
+  };
+
+public:
+
+  /**
+   * @brief This is the constructor for applications without an argument list.
+   * @since_tizen 2.4
+   * @privlevel public
+   * @privilege %http://tizen.org/privilege/display
+   */
+  static Application New();
+
+  /**
+   * @brief This is the constructor for applications.
+   *
+   * @since_tizen 2.4
+   * @privlevel public
+   * @privilege %http://tizen.org/privilege/display
+   * @param[in,out]  argc        A pointer to the number of arguments
+   * @param[in,out]  argv        A pointer the the argument list
+   */
+  static Application New( int* argc, char **argv[] );
+
+  /**
+   * @brief This is the constructor for applications with a name
+   *
+   * @since_tizen 2.4
+   * @privlevel public
+   * @privilege %http://tizen.org/privilege/display
+   * @param[in,out]  argc        A pointer to the number of arguments
+   * @param[in,out]  argv        A pointer the the argument list
+   * @param[in]      stylesheet  The path to user defined theme file
+   */
+  static Application New( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * @brief This is the constructor for applications with a name
+   *
+   * @since_tizen 2.4
+   * @privlevel public
+   * @privilege %http://tizen.org/privilege/display
+   * @param[in,out]  argc        A pointer to the number of arguments
+   * @param[in,out]  argv        A pointer the the argument list
+   * @param[in]      stylesheet  The path to user defined theme file
+   * @param[in]      windowMode  A member of WINDOW_MODE
+   */
+  static Application New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+  /**
+   * @brief Construct an empty handle
+   * @since_tizen 2.4
+   */
+  Application();
+
+  /**
+   * @brief Copy Constructor
+   * @since_tizen 2.4
+   */
+  Application( const Application& application );
+
+  /**
+   * @brief Assignment operator
+   * @since_tizen 2.4
+   */
+  Application& operator=( const Application& applicaton );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @since_tizen 2.4
+   */
+  ~Application();
+
+public:
+  /**
+   * @brief This starts the application. Choosing this form of main loop indicates that the default
+   * application configuration of APPLICATION_HANDLES_CONTEXT_LOSS is used. On platforms where
+   * context loss can occur, the application is responsible for tearing down and re-loading UI.
+   * The application should listen to Stage::ContextLostSignal and Stage::ContextRegainedSignal.
+   * @since_tizen 2.4
+   */
+  void MainLoop();
+
+  /**
+   * @brief This starts the application, and allows the app to choose a different configuration.
+   * If the application plans on using the ReplaceSurface or ReplaceWindow API, then this will
+   * trigger context loss & regain.
+   * The application should listen to Stage::ContextLostSignal and Stage::ContextRegainedSignal.
+   * @since_tizen 2.4
+   */
+  void MainLoop(Configuration::ContextLoss configuration);
+
+  /**
+   * @brief This lowers the application to bottom without actually quitting it
+   * @since_tizen 2.4
+   */
+  void Lower();
+
+  /**
+   * @brief This quits the application.  Tizen applications should use Lower to improve re-start performance unless they need to Quit completely.
+   * @since_tizen 2.4
+   */
+  void Quit();
+
+  /**
+   * @brief Ensures that the function passed in is called from the main loop when it is idle.
+   * @since_tizen 2.4
+   * @param[in]  callback  The function to call.
+   * @return true if added successfully, false otherwise
+   *
+   * @note Function must be called from main event thread only
+   *
+   * A callback of the following type may be used:
+   * @code
+   *   void MyFunction();
+   * @endcode
+   *
+   * @note Ownership of the callback is passed onto this class.
+   */
+  bool AddIdle( CallbackBase* callback );
+
+  /**
+   * @brief Retrieves the window used by the Application class.
+   * The application writer can use the window to change indicator and orientation
+   * properties.
+   * @since_tizen 2.4
+   * @return A handle to the window
+   */
+  Window GetWindow();
+
+  /**
+   * @brief Replace the current window.
+   * This will force context loss.
+   * If you plan on using this API in your application, then you should configure
+   * it to prevent discard behaviour when handling the Init signal.
+   * @since_tizen 2.4
+   * @param[in] windowPosition The position and size parameters of the new window
+   * @param[in] name The name of the new window
+   */
+  void ReplaceWindow(PositionSize windowPosition, const std::string& name);
+
+public: // Stereoscopy
+
+  /**
+   * @brief Set the viewing mode for the application.
+   * @since_tizen 2.4
+   * @param[in] viewMode The new viewing mode.
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @brief Get the current viewing mode.
+   * @since_tizen 2.4
+   * @return The current viewing mode.
+   */
+  ViewMode GetViewMode() const;
+
+  /**
+   * @brief Set the stereo base (eye separation) for Stereoscopic 3D
+   *
+   * @since_tizen 2.4
+   * @param[in] stereoBase The stereo base (eye separation) for Stereoscopic 3D
+   */
+  void SetStereoBase( float stereoBase );
+
+  /**
+   * @brief Get the stereo base (eye separation) for Stereoscopic 3D
+   *
+   * @since_tizen 2.4
+   * @return The stereo base (eye separation) for Stereoscopic 3D
+   */
+  float GetStereoBase() const;
+
+public:  // Signals
+
+  /**
+   * @brief The user should connect to this signal to determine when they should initialise
+   * their application.
+   * @since_tizen 2.4
+   */
+  AppSignalType& InitSignal();
+
+  /**
+   * @brief The user should connect to this signal to determine when they should terminate
+   * their application
+   * @since_tizen 2.4
+   */
+  AppSignalType& TerminateSignal();
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any special
+   * activities when the application is about to be paused.
+   * @since_tizen 2.4
+   */
+  AppSignalType& PauseSignal();
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any special
+   * activities when the application has resumed.
+   * @since_tizen 2.4
+   */
+  AppSignalType& ResumeSignal();
+
+  /**
+   * @brief This signal is sent when the system requires the user to reinitialise itself.
+   * @since_tizen 2.4
+   */
+  AppSignalType& ResetSignal();
+
+  /**
+   * @brief This signal is emitted when the window the application is rendering on is resized.
+   * @since_tizen 2.4
+   */
+  AppSignalType& ResizeSignal();
+
+  /**
+  * @brief This signal is emitted when another application sends a launch request to the application.
+  * When the application is launched, this signal is emitted after the main loop of the application starts up.
+  * The passed parameter describes the launch request and contains the information about why the application is launched.
+  * @since_tizen 2.4
+  */
+  AppControlSignalType& AppControlSignal();
+
+  /**
+   * @brief This signal is emitted when the language is changed on the device.
+   * @since_tizen 2.4
+   */
+  AppSignalType& LanguageChangedSignal();
+
+  /**
+  * @brief This signal is emitted when the region of the device is changed.
+  * @since_tizen 2.4
+  */
+  AppSignalType& RegionChangedSignal();
+
+  /**
+  * @brief This signal is emitted when the battery level of the device is low.
+  * @since_tizen 2.4
+  */
+  AppSignalType& BatteryLowSignal();
+
+  /**
+  * @brief This signal is emitted when the memory level of the device is low.
+  * @since_tizen 2.4
+  */
+  AppSignalType& MemoryLowSignal();
+
+public: // Not intended for application developers
+  /**
+   * @brief Internal constructor
+   * @since_tizen 2.4
+   */
+  explicit DALI_INTERNAL Application(Internal::Adaptor::Application* application);
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_APPLICATION_H__
diff --git a/adaptors/public-api/adaptor-framework/input-method.h b/adaptors/public-api/adaptor-framework/input-method.h
new file mode 100644 (file)
index 0000000..3eab4bb
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __DALI_INPUT_MEHTOD_H__
+#define __DALI_INPUT_MEHTOD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace InputMethod
+{
+/**
+ * @brief Specifies what the Input Method "action" button functionality is set to.
+ *
+ * The 'Action' button is traditionally the [RETURN] or [DONE] button.
+ *
+ * Not all these actions are supported by all systems
+ *
+ * Setting a custom label will still require one of these actions to be set.
+ * @since_tizen 2.4
+ */
+enum ActionButton
+{
+  ACTION_DEFAULT,
+  ACTION_DONE,
+  ACTION_GO,
+  ACTION_JOIN,
+  ACTION_LOGIN,
+  ACTION_NEXT,
+  ACTION_PREVIOUS,
+  ACTION_SEARCH,
+  ACTION_SEND,
+  ACTION_SIGNIN,
+  ACTION_UNSPECIFIED,
+  ACTION_NONE
+};
+
+/**
+ * @brief Settings that can be changed in the system Input Method
+ *
+ * Not all these settings are supported by all systems
+ * @since_tizen 2.4
+ */
+enum Settings
+{
+  ACTION_BUTTON,          // ActionButton // Apply the one of the ActionButton functions to the action button (return button)
+  AUTO_CAPITALISE,        // boolean      // Capitalise first letter of each sentence automatically
+  AUTO_COMPLETE,          // boolean      // Suggest words based on the current input
+  AUTO_CORRECT            // boolean      // Automatically correct commonly misspelt words
+};
+
+} // namespace InputMethod
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_INPUT_MEHTOD_H__
diff --git a/adaptors/public-api/adaptor-framework/key.cpp b/adaptors/public-api/adaptor-framework/key.cpp
new file mode 100644 (file)
index 0000000..cfa2509
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <key.h>
+
+// INTERNAL INCLUDES
+#include <key-impl.h>
+
+namespace Dali
+{
+
+bool IsKey( const KeyEvent& keyEvent, KEY daliKey)
+{
+  return Internal::Adaptor::KeyLookup::IsKey( keyEvent, daliKey );
+}
+
+}
diff --git a/adaptors/public-api/adaptor-framework/key.h b/adaptors/public-api/adaptor-framework/key.h
new file mode 100644 (file)
index 0000000..d8abbf6
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef __DALI_KEY_H__
+#define __DALI_KEY_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+#include <dali/public-api/events/key-event.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Mapping of keyboard and mouse button event keycodes to platform specific codes.
+ * @since_tizen 2.4
+ */
+
+enum KEY
+{
+  DALI_KEY_INVALID          = -1,
+  DALI_KEY_ESCAPE           = 9,
+  DALI_KEY_BACKSPACE        = 22,
+  DALI_KEY_SHIFT_LEFT       = 50,
+  DALI_KEY_SHIFT_RIGHT      = 62,
+  DALI_KEY_CURSOR_UP        = 111,
+  DALI_KEY_CURSOR_LEFT      = 113,
+  DALI_KEY_CURSOR_RIGHT     = 114,
+  DALI_KEY_CURSOR_DOWN      = 116,
+  DALI_KEY_BACK             = 166,
+  DALI_KEY_CAMERA           = 167,
+  DALI_KEY_CONFIG           = 168,
+  DALI_KEY_POWER            = 169,
+  DALI_KEY_PAUSE            = 170,
+  DALI_KEY_CANCEL           = 171,
+  DALI_KEY_PLAY_CD          = 172,
+  DALI_KEY_STOP_CD          = 173,
+  DALI_KEY_PAUSE_CD         = 174,
+  DALI_KEY_NEXT_SONG        = 175,
+  DALI_KEY_PREVIOUS_SONG    = 176,
+  DALI_KEY_REWIND           = 177,
+  DALI_KEY_FASTFORWARD      = 178,
+  DALI_KEY_MEDIA            = 179,
+  DALI_KEY_PLAY_PAUSE       = 180,
+  DALI_KEY_MUTE             = 181,
+  DALI_KEY_MENU             = 182,
+  DALI_KEY_HOME             = 183,
+  DALI_KEY_HOMEPAGE         = 187,
+  DALI_KEY_WEBPAGE          = 188,
+  DALI_KEY_MAIL             = 189,
+  DALI_KEY_SCREENSAVER      = 190,
+  DALI_KEY_BRIGHTNESS_UP    = 191,
+  DALI_KEY_BRIGHTNESS_DOWN  = 192,
+  DALI_KEY_SOFT_KBD         = 193,
+  DALI_KEY_QUICK_PANEL      = 194,
+  DALI_KEY_TASK_SWITCH      = 195,
+  DALI_KEY_APPS             = 196,
+  DALI_KEY_SEARCH           = 197,
+  DALI_KEY_VOICE            = 198,
+  DALI_KEY_LANGUAGE         = 199,
+  DALI_KEY_VOLUME_UP        = 200,
+  DALI_KEY_VOLUME_DOWN      = 201
+};
+
+/**
+ * @brief Check if a key event is for a specific DALI KEY.
+ *
+ * @since_tizen 2.4
+ * @param keyEvent reference to a keyEvent structure
+ * @param daliKey dali key enum
+ * @return true if the key is matched, false if not
+ */
+DALI_IMPORT_API bool IsKey( const KeyEvent& keyEvent, KEY daliKey);
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_KEY_H__
diff --git a/adaptors/public-api/adaptor-framework/native-image-source.cpp b/adaptors/public-api/adaptor-framework/native-image-source.cpp
new file mode 100644 (file)
index 0000000..ba9a914
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <native-image-source.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <native-image-source-impl.h>
+
+namespace Dali
+{
+
+NativeImageSourcePtr NativeImageSource::New( unsigned int width, unsigned int height, ColorDepth depth )
+{
+  Any empty;
+  NativeImageSourcePtr image = new NativeImageSource( width, height, depth, empty );
+  return image;
+}
+
+Any NativeImageSource::GetNativeImageSource()
+{
+  return mImpl->GetNativeImageSource();
+}
+
+NativeImageSourcePtr NativeImageSource::New( Any nativeImageSource )
+{
+  NativeImageSourcePtr image = new NativeImageSource(0, 0, COLOR_DEPTH_DEFAULT, nativeImageSource);
+  return image;
+}
+
+bool NativeImageSource::GetPixels( std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const
+{
+  return mImpl->GetPixels( pixbuf, width, height, pixelFormat );
+}
+
+bool NativeImageSource::EncodeToFile(const std::string& filename) const
+{
+  return mImpl->EncodeToFile(filename);
+}
+
+bool NativeImageSource::GlExtensionCreate()
+{
+  return mImpl->GlExtensionCreate();
+}
+
+void NativeImageSource::GlExtensionDestroy()
+{
+  mImpl->GlExtensionDestroy();
+}
+
+unsigned int NativeImageSource::TargetTexture()
+{
+  return mImpl->TargetTexture();
+}
+
+void NativeImageSource::PrepareTexture()
+{
+
+}
+
+unsigned int NativeImageSource::GetWidth() const
+{
+  return mImpl->GetWidth();
+}
+
+unsigned int NativeImageSource::GetHeight() const
+{
+  return mImpl->GetHeight();
+}
+
+bool NativeImageSource::RequiresBlending() const
+{
+  return mImpl->RequiresBlending();
+}
+
+NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource )
+{
+   mImpl = Internal::Adaptor::NativeImageSource::New( width, height, depth, nativeImageSource );
+}
+
+NativeImageSource::~NativeImageSource()
+{
+  delete mImpl;
+}
+
+} // namespace Dali
diff --git a/adaptors/public-api/adaptor-framework/native-image-source.h b/adaptors/public-api/adaptor-framework/native-image-source.h
new file mode 100644 (file)
index 0000000..c9af690
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef __DALI_NATIVE_IMAGE_SOURCE_H__
+#define __DALI_NATIVE_IMAGE_SOURCE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/images/native-image-interface.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/object/any.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class NativeImageSource;
+}
+}
+
+class NativeImageSource;
+/**
+ * @brief Pointer to Dali::NativeImageSource.
+ * @since_tizen 2.4
+ */
+typedef IntrusivePtr<NativeImageSource> NativeImageSourcePtr;
+
+/**
+ * @brief Used for displaying native images.
+ *
+ * The native image source can be created internally or
+ * externally by X11 or ECORE-X11.
+ *
+ * @since_tizen 2.4
+ */
+class DALI_IMPORT_API NativeImageSource : public NativeImageInterface
+{
+public:
+
+   /**
+    * @brief When creating a native image the color depth has to be specified.
+    * @since_tizen 2.4
+    */
+   enum ColorDepth
+   {
+     COLOR_DEPTH_DEFAULT,     ///< Uses the current X screen default depth (recommended)
+     COLOR_DEPTH_8,           ///< 8 bits per pixel
+     COLOR_DEPTH_16,          ///< 16 bits per pixel
+     COLOR_DEPTH_24,          ///< 24 bits per pixel
+     COLOR_DEPTH_32           ///< 32 bits per pixel
+   };
+
+  /**
+   * @brief Create a new NativeImageSource.
+   *
+   * Depending on hardware the width and height may have to be a power of two.
+   * @since_tizen 2.4
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] depth color depth of the image
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourcePtr New( unsigned int width, unsigned int height, ColorDepth depth );
+
+  /**
+   * @brief Create a new NativeImageSource from an existing native image.
+   *
+   * @since_tizen 2.4
+   * @param[in] nativeImageSource must be a X11 pixmap or a Ecore_X_Pixmap now.
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourcePtr New( Any nativeImageSource );
+
+  /**
+   * @brief Retrieve the internal native image.
+   *
+   * @since_tizen 2.4
+   * @return Any object containing the internal native image.
+   */
+  Any GetNativeImageSource();
+
+  /**
+   * @brief Get a copy of the pixels used by NativeImageSource.
+   *
+   * This is only supported for 24 bit RGB and 32 bit RGBA internal formats
+   * (COLOR_DEPTH_24 and COLOR_DEPTH_32).
+   * @since_tizen 2.4
+   * @param[out] pixbuf a vector to store the pixels in
+   * @param[out] width  width of image
+   * @param[out] height height of image
+   * @param[out] pixelFormat pixel format used by image
+   * @return     True if the pixels were gotten, and false otherwise.
+   */
+  bool GetPixels( std::vector<unsigned char>& pixbuf, unsigned int& width, unsigned int& height, Pixel::Format& pixelFormat ) const;
+
+  /**
+   * @brief Convert the current pixel contents to either a JPEG or PNG format
+   * and write that to the filesytem.
+   *
+   * @since_tizen 2.4
+   * @param[in] filename Identify the filesytem location at which to write the
+   *                     encoded image. The extension determines the encoding used.
+   *                     The two valid encoding are (".jpeg"|".jpg") and ".png".
+   * @return    True if the pixels were written, and false otherwise.
+   */
+  bool EncodeToFile(const std::string& filename) const;
+
+private:   // native image
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual unsigned int GetWidth() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual unsigned int GetHeight() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const;
+
+private:
+
+  /**
+   * @brief Private constructor
+   * @since_tizen 2.4
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] depth color depth of the image
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  DALI_INTERNAL NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   *
+   * The implementation should destroy the NativeImage resources.
+   * @since_tizen 2.4
+   */
+  DALI_INTERNAL virtual ~NativeImageSource();
+
+  /**
+   * @brief Undefined copy constructor
+   *
+   * This avoids accidental calls to a default copy constructor.
+   * @since_tizen 2.4
+   * @param[in] rhs A reference to the object to copy.
+   */
+  DALI_INTERNAL NativeImageSource( const NativeImageSource& nativeImageSource );
+
+  /**
+   * @brief Undefined assignment operator.
+   *
+   * This avoids accidental calls to a default assignment operator.
+   * @since_tizen 2.4
+   * @param[in] rhs A reference to the object to copy.
+   */
+  DALI_INTERNAL NativeImageSource& operator=(const NativeImageSource& rhs);
+
+private:
+
+  Internal::Adaptor::NativeImageSource* mImpl; ///< Implementation pointer
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_NATIVE_IMAGE_SOURCE_H__
diff --git a/adaptors/public-api/adaptor-framework/style-change.h b/adaptors/public-api/adaptor-framework/style-change.h
new file mode 100644 (file)
index 0000000..0765f56
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __DALI_STYLE_CHANGE_H__
+#define __DALI_STYLE_CHANGE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace StyleChange
+{
+
+enum Type
+{
+  DEFAULT_FONT_CHANGE,      ///< Denotes that the default font has changed.
+  DEFAULT_FONT_SIZE_CHANGE, ///< Denotes that the default font size has changed.
+  THEME_CHANGE              ///< Denotes that the theme has changed.
+};
+
+} // namespace StyleChange
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_STYLE_CHANGE_H__
diff --git a/adaptors/public-api/adaptor-framework/timer.cpp b/adaptors/public-api/adaptor-framework/timer.cpp
new file mode 100644 (file)
index 0000000..b8c6e5c
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <timer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <timer-impl.h>
+
+namespace Dali
+{
+
+Timer::Timer()
+{
+}
+
+Timer Timer::New( unsigned int milliSec )
+{
+  Internal::Adaptor::TimerPtr internal = Internal::Adaptor::Timer::New( milliSec );
+  return Timer(internal.Get());
+}
+
+Timer::Timer( const Timer& timer )
+: BaseHandle(timer)
+{
+}
+
+Timer& Timer::operator=( const Timer& timer )
+{
+  // check self assignment
+  if( *this != timer )
+  {
+    BaseHandle::operator=(timer);
+  }
+  return *this;
+}
+
+Timer::~Timer()
+{
+}
+
+Timer Timer::DownCast( BaseHandle handle )
+{
+  return Timer( dynamic_cast<Internal::Adaptor::Timer*>( handle.GetObjectPtr() ) );
+}
+
+void Timer::Start()
+{
+  Internal::Adaptor::GetImplementation(*this).Start();
+}
+
+void Timer::Stop()
+{
+  Internal::Adaptor::GetImplementation(*this).Stop();
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  Internal::Adaptor::GetImplementation(*this).SetInterval( interval );
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetInterval();
+}
+
+bool Timer::IsRunning() const
+{
+  return Internal::Adaptor::GetImplementation(*this).IsRunning();
+}
+
+Timer::TimerSignalType& Timer::TickSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TickSignal();
+}
+
+Timer::Timer(Internal::Adaptor::Timer* timer)
+: BaseHandle(timer)
+{
+}
+
+
+} // namespace Dali
diff --git a/adaptors/public-api/adaptor-framework/timer.h b/adaptors/public-api/adaptor-framework/timer.h
new file mode 100644 (file)
index 0000000..cbe67ff
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef __DALI_TIMER_H__
+#define __DALI_TIMER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Timer;
+}
+}
+
+/**
+ * @brief Mechanism to issue simple periodic or one-shot events.
+ *
+ * Timer is provided for application developers to be able to issue
+ * simple periodic or one-shot events.  Please note that timer
+ * callback functions should return as soon as possible, because they
+ * block the next SignalTick.  Please note that timer signals are not
+ * in sync with Dali's render timer.
+ *
+ * This class is a handle class so it can be stack allocated and used
+ * as a member.
+ * @since_tizen 2.4
+ */
+class DALI_IMPORT_API Timer : public BaseHandle
+{
+public: // Signal typedefs
+
+  typedef Signal< bool () > TimerSignalType; ///< Timer finished signal callback type
+
+public: // API
+
+  /**
+   * @brief Constructor, creates an uninitialized timer.
+   *
+   * Call New to fully construct a timer.
+   * @since_tizen 2.4
+   */
+  Timer();
+
+  /**
+   * @brief Create an tick Timer that emits periodic signal.
+   *
+   * @since_tizen 2.4
+   * @param[in] milliSec Interval in milliseconds.
+   * @return a new timer
+   */
+  static Timer New( unsigned int milliSec );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @since_tizen 2.4
+   * @param[in] timer The handle to copy. The copied handle will point at the same implementation
+   */
+  Timer( const Timer& timer );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @since_tizen 2.4
+   * @param[in] timer The handle to copy. This handle will point at the same implementation
+   * as the copied handle.
+   * @return Reference to this timer handle
+   */
+  Timer& operator=( const Timer& timer );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @since_tizen 2.4
+   */
+  ~Timer();
+
+  /**
+   * @brief Downcast an Object handle to Timer handle.
+   *
+   * If handle points to a Timer object the downcast produces a valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @since_tizen 2.4
+   * @param[in] handle to An object
+   * @return handle to a Timer object or an uninitialized handle
+   */
+  static Timer DownCast( BaseHandle handle );
+
+  /**
+   * @brief Start timer.
+   *
+   * In case a Timer is already running it's time is reset and timer is restarted.
+   * @since_tizen 2.4
+   */
+  void Start();
+
+  /**
+   * @brief Stop timer.
+   * @since_tizen 2.4
+   */
+  void Stop();
+
+  /**
+   * @brief Sets a new interval on the timer and starts the timer.
+   *
+   * Cancels the previous timer.
+   * @since_tizen 2.4
+   * @param  milliSec Interval in milliseconds.
+   */
+  void SetInterval( unsigned int milliSec );
+
+  /**
+   * @brief Get the interval of timer.
+   * @returns  Interval in milliseconds.
+   * @since_tizen 2.4
+   */
+  unsigned int GetInterval() const;
+
+  /**
+   * @brief  Tells whether timer is running.
+   * @since_tizen 2.4
+   * @return Whether Timer is started or not.
+   */
+  bool IsRunning() const;
+
+public: // Signals
+
+  /**
+   * @brief Signal emitted after specified time interval.
+   *
+   * The return of the callback decides whether signal emission stops or continues.
+   * If the callback function returns false emission will stop, if true it will continue
+   * This return value is ignored for one-shot events, which will always stop after the first execution.
+   * @returns The signal to Connect() with.
+   * @since_tizen 2.4
+   */
+  TimerSignalType& TickSignal();
+
+public: // Not intended for application developers
+  explicit DALI_INTERNAL Timer(Internal::Adaptor::Timer* timer);
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_TIMER_H__
diff --git a/adaptors/public-api/adaptor-framework/tts-player.cpp b/adaptors/public-api/adaptor-framework/tts-player.cpp
new file mode 100644 (file)
index 0000000..0ac4a4b
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <tts-player.h>
+
+// INTERNAL INCLUDES
+#include <tts-player-impl.h>
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+TtsPlayer::TtsPlayer()
+{
+}
+
+TtsPlayer TtsPlayer::Get(Dali::TtsPlayer::Mode mode)
+{
+  TtsPlayer ttsPlayer;
+
+  if ( Adaptor::IsAvailable() )
+  {
+    ttsPlayer = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTtsPlayer(mode);
+  }
+
+  return ttsPlayer;
+}
+
+TtsPlayer::~TtsPlayer()
+{
+}
+
+TtsPlayer::TtsPlayer(const TtsPlayer& handle)
+: BaseHandle(handle)
+{
+}
+
+TtsPlayer& TtsPlayer::operator=(const TtsPlayer& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void TtsPlayer::Play(const std::string& text)
+{
+  GetImplementation(*this).Play(text);
+}
+
+void TtsPlayer::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+void TtsPlayer::Pause()
+{
+  GetImplementation(*this).Pause();
+}
+
+void TtsPlayer::Resume()
+{
+  GetImplementation(*this).Resume();
+}
+
+TtsPlayer::State TtsPlayer::GetState()
+{
+  return GetImplementation(*this).GetState();
+}
+
+TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  return GetImplementation(*this).StateChangedSignal();
+}
+
+TtsPlayer::TtsPlayer( Internal::Adaptor::TtsPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/public-api/adaptor-framework/tts-player.h b/adaptors/public-api/adaptor-framework/tts-player.h
new file mode 100644 (file)
index 0000000..acc9f2a
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef __DALI_TTS_PLAYER_H__
+#define __DALI_TTS_PLAYER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class TtsPlayer;
+}
+}
+
+/**
+ * @brief The Text-to-speech Player.
+ * @since_tizen 2.4
+ */
+class DALI_IMPORT_API TtsPlayer : public BaseHandle
+{
+public: // ENUMs
+
+  /**
+   * @brief Enumeration of TTS mode.
+   * @since_tizen 2.4
+   */
+  enum Mode
+  {
+    DEFAULT = 0,  ///< Default mode for normal application
+    NOTIFICATION, ///< Notification mode
+    SCREEN_READER, ///< Screen reader mode
+    MODE_NUM
+  };
+
+  /**
+   * @brief Enumeration of TTS state.
+   * @since_tizen 2.4
+   */
+  enum State
+  {
+    UNAVAILABLE = 0,    ///< Player is not available
+    READY,              ///< Player is ready to play
+    PLAYING,            ///< Player is playing
+    PAUSED              ///< Player is paused
+  };
+
+public: // Typedefs
+
+  /**
+   * @brief Type of signal emitted when the TTS state changes.
+   * @since_tizen 2.4
+   */
+  typedef Signal< void ( const Dali::TtsPlayer::State, const Dali::TtsPlayer::State ) > StateChangedSignalType;
+
+public: // API
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling TtsPlayer::Get().
+   * @since_tizen 2.4
+   */
+  TtsPlayer();
+
+  /**
+   * @brief Gets the singleton of the TtsPlayer for the given mode.
+   *
+   * @since_tizen 2.4
+   * @param mode the mode of tts-player
+   * @return A handle of the Ttsplayer for the given mode.
+   */
+  static TtsPlayer Get(Dali::TtsPlayer::Mode mode = Dali::TtsPlayer::DEFAULT);
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @since_tizen 2.4
+   */
+  ~TtsPlayer();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @since_tizen 2.4
+   * @param [in] handle A reference to the copied handle
+   */
+  TtsPlayer(const TtsPlayer& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @since_tizen 2.4
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  TtsPlayer& operator=(const TtsPlayer& rhs);
+
+  /**
+   * @brief Start playing the audio data synthesized from the specified text.
+   *
+   * @since_tizen 2.4
+   * @param[in] text to play.
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Play(const std::string& text);
+
+  /**
+   * @brief Stops playing the utterance.
+   * @since_tizen 2.4
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Stop();
+
+  /**
+   * @brief Pauses the currently playing utterance.
+   * @since_tizen 2.4
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes the previously paused utterance.
+   * @since_tizen 2.4
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Resume();
+
+  /**
+   * @brief Gets the current state of the player.
+   * @since_tizen 2.4
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  State GetState();
+
+  /**
+   * @brief Allows connection TTS state change signal.
+   * Note: Only supported by some adaptor types.
+   * @since_tizen 2.4
+   * @return A reference to the signal for connection.
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by TtsPlayer::Get().
+   * @since_tizen 2.4
+   * @param[in] ttsPlayer A pointer to the TTS player.
+   */
+  explicit DALI_INTERNAL TtsPlayer( Internal::Adaptor::TtsPlayer* ttsPlayer );
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_TTS_PLAYER_H__
diff --git a/adaptors/public-api/adaptor-framework/window.cpp b/adaptors/public-api/adaptor-framework/window.cpp
new file mode 100644 (file)
index 0000000..bb1b4cc
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <window.h>
+
+// INTERNAL INCLUDES
+#include <window-impl.h>
+#include <orientation-impl.h>
+
+namespace Dali
+{
+
+Window Window::New(PositionSize posSize, const std::string& name, bool isTransparent)
+{
+  Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(posSize, name, "", isTransparent);
+  return Window(window);
+}
+
+Window Window::New(PositionSize posSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(posSize, name, className, isTransparent);
+  return Window(window);
+}
+
+Window::Window()
+{
+}
+
+Window::~Window()
+{
+}
+
+Window::Window(const Window& handle)
+: BaseHandle(handle)
+{
+}
+
+Window& Window::operator=(const Window& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void Window::ShowIndicator( IndicatorVisibleMode visibleMode )
+{
+  GetImplementation(*this).ShowIndicator( visibleMode );
+}
+
+Window::IndicatorSignalType& Window::IndicatorVisibilityChangedSignal()
+{
+  return GetImplementation(*this).IndicatorVisibilityChangedSignal();
+}
+
+void Window::SetIndicatorBgOpacity( IndicatorBgOpacity opacity )
+{
+  GetImplementation(*this).SetIndicatorBgOpacity( opacity );
+}
+
+void Window::RotateIndicator( WindowOrientation orientation )
+{
+  GetImplementation(*this).RotateIndicator( orientation );
+}
+
+void Window::SetClass( std::string name, std::string klass )
+{
+  GetImplementation(*this).SetClass( name, klass );
+}
+
+void Window::Raise()
+{
+  GetImplementation(*this).Raise();
+}
+
+void Window::Lower()
+{
+  GetImplementation(*this).Lower();
+}
+
+void Window::Activate()
+{
+  GetImplementation(*this).Activate();
+}
+
+void Window::AddAvailableOrientation( WindowOrientation orientation )
+{
+  GetImplementation(*this).AddAvailableOrientation( orientation );
+}
+
+void Window::RemoveAvailableOrientation( WindowOrientation orientation )
+{
+  GetImplementation(*this).RemoveAvailableOrientation( orientation );
+}
+
+void Window::SetPreferredOrientation( Dali::Window::WindowOrientation orientation )
+{
+  GetImplementation(*this).SetPreferredOrientation( orientation );
+}
+
+Dali::Window::WindowOrientation Window::GetPreferredOrientation()
+{
+  return GetImplementation(*this).GetPreferredOrientation();
+}
+
+DragAndDropDetector Window::GetDragAndDropDetector() const
+{
+  return GetImplementation(*this).GetDragAndDropDetector();
+}
+
+Any Window::GetNativeHandle() const
+{
+  return GetImplementation(*this).GetNativeHandle();
+}
+
+Window::Window( Internal::Adaptor::Window* window )
+: BaseHandle( window )
+{
+}
+
+} // namespace Dali
diff --git a/adaptors/public-api/adaptor-framework/window.h b/adaptors/public-api/adaptor-framework/window.h
new file mode 100644 (file)
index 0000000..48cd640
--- /dev/null
@@ -0,0 +1,268 @@
+#ifndef __DALI_WINDOW_H__
+#define __DALI_WINDOW_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+typedef Dali::Rect<int> PositionSize;
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Window;
+}
+}
+
+class DragAndDropDetector;
+class Orientation;
+
+/**
+ * @brief The window class is used internally for drawing.
+ *
+ * It has an orientation
+ * and indicator properties.
+ * @since_tizen 2.4
+ */
+class DALI_IMPORT_API Window : public BaseHandle
+{
+public:
+  typedef Signal< void (bool) > IndicatorSignalType;
+
+public:
+
+  // Enumerations
+
+  /**
+   * @brief Orientation of the window.
+   * @since_tizen 2.4
+   */
+  enum WindowOrientation
+  {
+    PORTRAIT = 0,
+    LANDSCAPE = 90,
+    PORTRAIT_INVERSE = 180,
+    LANDSCAPE_INVERSE = 270
+  };
+
+  /**
+   * @brief Opacity of the indicator.
+   * @since_tizen 2.4
+   */
+  enum IndicatorBgOpacity
+  {
+    OPAQUE = 100, // Fully opaque indicator Bg
+    TRANSLUCENT = 50, // Semi translucent indicator Bg
+    TRANSPARENT = 0 // Fully transparent indicator Bg
+  };
+
+  /**
+   * @brief Visible mode of the indicator.
+   * @since_tizen 2.4
+   */
+  enum IndicatorVisibleMode
+  {
+    INVISIBLE = 0, // hide indicator
+    VISIBLE = 1, // show indicator
+    AUTO = 2 // hide in default, will show when necessary
+  };
+
+  // Methods
+
+  /**
+   * @brief Create an initialized handle to a new Window.
+   * @since_tizen 2.4
+   * @param[in] windowPosition The position and size of the window
+   * @param[in] name The window title
+   * @param[in] isTransparent Whether window is transparent
+   * @return a new window
+   */
+  static Window New(PositionSize windowPosition, const std::string& name, bool isTransparent = false);
+
+  /**
+   * @brief Create an initialized handle to a new Window.
+   * @since_tizen 2.4
+   * @param[in] windowPosition The position and size of the window
+   * @param[in] name The window title
+   * @param[in] className The window class name
+   * @param[in] isTransparent Whether window is transparent
+   * @return a new window
+   */
+  static Window New(PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  /**
+   * @brief Create an uninitalized handle.
+   *
+   * This can be initialized using Dali::Application::GetWindow() or
+   * Dali::Window::New()
+   * @since_tizen 2.4
+   */
+  Window();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @since_tizen 2.4
+   */
+  ~Window();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @since_tizen 2.4
+   * @param [in] handle A reference to the copied handle
+   */
+  Window(const Window& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @since_tizen 2.4
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  Window& operator=(const Window& rhs);
+
+  /**
+   * @brief This sets whether the indicator bar should be shown or not.
+   * @since_tizen 2.4
+   * @param[in] visibleMode visible mode for indicator bar, VISIBLE in default
+   */
+  void ShowIndicator( IndicatorVisibleMode visibleMode );
+
+  /**
+   * @brief This sets the opacity mode of indicator bar.
+   * @since_tizen 2.4
+   * @param[in] opacity - The opacity mode
+   */
+  void SetIndicatorBgOpacity( IndicatorBgOpacity opacity );
+
+  /**
+   * @brief This sets the orientation of indicator bar.
+   *
+   * It does not implicitly show the indicator if it is currently
+   * hidden.
+   * @since_tizen 2.4
+   * @param[in] orientation The orientation
+   */
+  void RotateIndicator(WindowOrientation orientation);
+
+  /**
+   * @brief Set the window name and class string.
+   * @since_tizen 2.4
+   * @param[in] name The name of the window
+   * @param[in] klass The class of the window
+   */
+  void SetClass(std::string name, std::string klass);
+
+  /**
+   * @brief Raise window to top of window stack.
+   * @since_tizen 2.4
+   */
+  void Raise();
+
+  /**
+   * @brief Lower window to bottom of window stack.
+   * @since_tizen 2.4
+   */
+  void Lower();
+
+  /**
+   * @brief Activate window to top of window stack even it is iconified.
+   * @since_tizen 2.4
+   */
+  void Activate();
+
+  /**
+   * @brief Add an orientation to the list of available orientations.
+   * @since_tizen 2.4
+   */
+  void AddAvailableOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Remove an orientation from the list of available orientations.
+   * @since_tizen 2.4
+   */
+  void RemoveAvailableOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Set a preferred orientation.
+   * @since_tizen 2.4
+   * @param[in] orientation The preferred orientation
+   * @pre orientation is in the list of available orientations
+   */
+  void SetPreferredOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Get the preferred orientation.
+   * @since_tizen 2.4
+   * @return The preferred orientation if previously set, or none.
+   */
+  WindowOrientation GetPreferredOrientation();
+
+  /**
+   * @brief Returns the Drag & drop detector which can be used to receive drag & drop events.
+   * @since_tizen 2.4
+   * @return A handle to the DragAndDropDetector.
+   */
+  DragAndDropDetector GetDragAndDropDetector() const;
+
+  /**
+   * @brief Get the native handle of the window.
+   * @since_tizen 2.4
+   * @return The native handle of the window or an empty handle.
+   */
+  Any GetNativeHandle() const;
+
+public: // Signals
+  /**
+   * @brief The user should connect to this signal to get a timing when indicator was shown / hidden.
+   * @since_tizen 2.4
+   */
+  IndicatorSignalType& IndicatorVisibilityChangedSignal();
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used by Dali::Application::GetWindow().
+   * @since_tizen 2.4
+   * @param[in] window A pointer to the window.
+   */
+  explicit DALI_INTERNAL Window( Internal::Adaptor::Window* window );
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_WINDOW_H__
diff --git a/adaptors/public-api/dali-adaptor-version.cpp b/adaptors/public-api/dali-adaptor-version.cpp
new file mode 100644 (file)
index 0000000..adb0d57
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include <dali-adaptor-version.h>
+
+// EXTERNAL INCLUDES
+#ifdef DEBUG_ENABLED
+#include <iostream>
+#endif
+
+namespace Dali
+{
+
+const unsigned int ADAPTOR_MAJOR_VERSION = 1;
+const unsigned int ADAPTOR_MINOR_VERSION = 0;
+const unsigned int ADAPTOR_MICRO_VERSION = 49;
+const char * const ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
+
+#ifdef DEBUG_ENABLED
+namespace
+{
+/// Allows the printing of the version number ONLY when debug is enabled
+struct PrintVersion
+{
+  PrintVersion()
+  {
+    std::cout << "DALi Adaptor:   " << ADAPTOR_MAJOR_VERSION << "." << ADAPTOR_MINOR_VERSION << "." << ADAPTOR_MICRO_VERSION << " (" << ADAPTOR_BUILD_DATE << ")" << std::endl;
+  }
+};
+PrintVersion ADAPTOR_VERSION;
+} // unnamed namespace
+#endif
+
+} // namespace Dali
diff --git a/adaptors/public-api/dali-adaptor-version.h b/adaptors/public-api/dali-adaptor-version.h
new file mode 100644 (file)
index 0000000..643b020
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef __DALI_ADAPTOR_VERSION_H__
+#define __DALI_ADAPTOR_VERSION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+DALI_IMPORT_API extern const unsigned int ADAPTOR_MAJOR_VERSION; ///< The major version number of the Adaptor.
+DALI_IMPORT_API extern const unsigned int ADAPTOR_MINOR_VERSION; ///< The minor version number of the Adaptor.
+DALI_IMPORT_API extern const unsigned int ADAPTOR_MICRO_VERSION; ///< The micro version number of the Adaptor.
+DALI_IMPORT_API extern const char * const ADAPTOR_BUILD_DATE;    ///< The date/time the Adaptor library was built.
+} // namespace Dali
+
+#endif // __DALI_ADAPTOR_VERSION_H__
diff --git a/adaptors/public-api/dali.h b/adaptors/public-api/dali.h
new file mode 100644 (file)
index 0000000..f1f7430
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __DALI_H__
+#define __DALI_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/dali-core.h>
+
+// Application / UI Framework adaption
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/public-api/adaptor-framework/input-method.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/adaptor-framework/tts-player.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+#include <dali/public-api/dali-adaptor-version.h>
+
+#endif //__DALI_H__
diff --git a/adaptors/public-api/file.list b/adaptors/public-api/file.list
new file mode 100644 (file)
index 0000000..dbf643f
--- /dev/null
@@ -0,0 +1,27 @@
+public_api_src_files = \
+  $(adaptor_public_api_dir)/adaptor-framework/application.cpp \
+  $(adaptor_public_api_dir)/adaptor-framework/key.cpp \
+  $(adaptor_public_api_dir)/adaptor-framework/window.cpp \
+  $(adaptor_public_api_dir)/adaptor-framework/timer.cpp \
+  $(adaptor_public_api_dir)/adaptor-framework/tts-player.cpp \
+  $(adaptor_public_api_dir)/adaptor-framework/native-image-source.cpp \
+  $(adaptor_public_api_dir)/dali-adaptor-version.cpp
+
+
+public_api_header_files = \
+  $(adaptor_public_api_dir)/dali-adaptor-version.h
+
+
+public_api_adaptor_framework_header_files = \
+  $(adaptor_public_api_dir)/adaptor-framework/application.h \
+  $(adaptor_public_api_dir)/adaptor-framework/application-configuration.h \
+  $(adaptor_public_api_dir)/adaptor-framework/input-method.h \
+  $(adaptor_public_api_dir)/adaptor-framework/key.h \
+  $(adaptor_public_api_dir)/adaptor-framework/style-change.h \
+  $(adaptor_public_api_dir)/adaptor-framework/timer.h \
+  $(adaptor_public_api_dir)/adaptor-framework/tts-player.h \
+  $(adaptor_public_api_dir)/adaptor-framework/native-image-source.h \
+  $(adaptor_public_api_dir)/adaptor-framework/window.h
+
+adaptor_dali_header_file = \
+  $(adaptor_public_api_dir)/dali.h
diff --git a/adaptors/scripts/dalireslog.sh b/adaptors/scripts/dalireslog.sh
new file mode 100755 (executable)
index 0000000..c1d8416
--- /dev/null
@@ -0,0 +1,748 @@
+#!/bin/bash
+# Log resource analyser tool for Dali
+# Monitors resource usage of last run Dali app
+# Shows memory uploaded to GPU or normal RAM
+# Texture atlas usage usually reflects used Font atlases
+
+set -u
+
+#global variables
+TERM_W=0       # latest width of terminal window
+TERM_H=0       # latest height of terminal window
+SEPARATOR_H=5  # 5 lines in info bar
+CURPAGE=0      # current page number
+MAXFILENO=0    # maximum lines to display from resourcelist
+MAXP=0         # number of pages
+
+DLOGTEMPFILE=/tmp/dalidlog.txt
+DLOGUTIL=/usr/bin/dlogutil
+USING_DLOG=
+INPUTFILE=""
+
+
+
+#possible states
+# ID| Desc                             | Color     | Tags
+#---+----------------------------------+-----------+-------
+# 0.| loaded in CPU memory             |  [CPU]    | [LOAD]
+# 1.| present in both memories         |  [CPUGPU] | [LOAD] [UPLOAD]
+# 2.| GPU memory only, buffer discarded|  [GPU]    | [UPLOAD] [DELBUF]
+# 3.| loaded but discarded later on    |  [DISC]   | [LOAD] [DELBUF] or [DELBUF] [DELTEXTURE]
+
+#colors for marking resource state
+COLOR_CPU=5
+COLOR_CPUGPU=1
+COLOR_GPU=2
+COLOR_DISC=6
+
+declare -a COLORS=( $COLOR_CPU $COLOR_CPUGPU $COLOR_GPU $COLOR_DISC )
+
+declare -a FILENAMES_G=( )
+declare -a BITMAPS_G=( )
+declare -a TEXTURES_G=( )
+declare -a STATES_G=( )
+declare -a SIZES_G=( )
+declare -a SIZE_DETAILS_G=( )
+
+ATLASMEM=0
+ATLAS_NO=0
+
+CPUMEM=0
+GPUMEM=0
+
+#process ID of last running Dali app
+PID_G=0
+
+#distinguish texture atlases from framebuffer textures
+BITMAP_ID_ATLAS=0
+BITMAP_ID_FB_TEXTURE="-"
+
+###################################string formatting, command line and error handling
+function error
+{
+  echo "Error: $1"
+  cleanup
+  exit 1
+}
+
+function usage
+{
+    echo "usage: ./dalireslog.sh [FILE]"
+    echo "if FILE isn't specified script will try to use dlogutil"
+}
+
+function getTermSize
+{
+    TERM_W=$(tput cols)
+    TERM_H=$(tput lines)
+
+    let MAXFILENO=$(($TERM_H-$SEPARATOR_H-2)) #leave space for keyboard shortcuts and separator itself
+    let MAXP=${#FILENAMES_G[@]}/$MAXFILENO
+
+    # don't show empty page if list just fits on screen
+    local rmd=0
+    let rmd=${#FILENAMES_G[@]}%$MAXFILENO
+    if [ $rmd -eq 0 ]
+    then
+        let MAXP-=1;
+    fi
+}
+
+# print string, notifying user if it doesn't fit in one line. takes one parameter
+function printString
+{
+    echo -n ${1:0:$TERM_W}
+    if [[ $TERM_W -lt ${#1} ]]
+    then
+        tput cub 1;
+        tput setab 1; tput smso; echo -n '>'; tput el; tput rmso
+        return 1
+    else
+        tput el
+        return 0
+    fi
+}
+
+# print string, clear until end of line, print newline. takes one parameter
+function printLine
+{
+    printString "$1"
+    local RET=$?
+    printf '\n'
+    return $RET
+}
+
+function parseCmdLine
+{
+    if [[ $# -lt 1 ]]
+    then
+        # try using dlogutil
+        if [[ ! -e "$DLOGUTIL" ]]
+        then
+            echo "dlogutil not installed"
+            usage
+            exit 1
+        fi
+
+        INPUTFILE="$DLOGTEMPFILE"
+        USING_DLOG=true
+    else
+        # check if help is requested
+        if [[ $1 == '-h' || $1 == '--help' ]]
+        then
+            usage
+            exit 0
+        # try reading from file
+        else
+            INPUTFILE=$1
+            if [[ ! -e "$INPUTFILE" ]]
+            then
+                echo cannot read file "$INPUTFILE"
+                usage
+                exit 1
+            fi
+        fi
+    fi
+}
+
+# print filename or basename or "..." depending on terminal size, takes one parameter
+function printPath
+{
+    if [ -z "$1" ]
+    then
+        echo "ERROR in printPath";
+        cleanup; exit 1
+    fi
+
+    FILENAME="$1"
+    FBASENAME=$(basename $FILENAME)
+    if [[ ${#FILENAME} -lt $TERM_W ]]
+    then
+        printLine "$FILENAME"
+    else
+        if [[ ${#FBASENAME} -lt $TERM_W ]]
+        then
+            printLine "$FBASENAME"
+        else
+            printLine ...
+        fi
+    fi
+}
+
+###################################memory query functions
+function getGpuMemUsage
+{
+  GPUMEM=0
+  local i=0
+  for state in ${STATES_G[@]}
+  do
+    if [[ $state == 1 || $state == 2 ]]
+    then
+      let GPUMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $GPUMEM
+}
+
+function getCpuMemUsage
+{
+  CPUMEM=0
+  local i=0
+  for state in ${STATES_G[@]}
+  do
+    if [[ $state == 0 || $state == 1 ]]
+    then
+      let CPUMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $CPUMEM
+}
+
+function getAtlasNumber
+{
+  ATLAS_NO=0
+  local i=0
+  for bitmap in ${BITMAPS_G[@]}
+  do
+    if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
+    then
+      let ATLAS_NO+=1
+    fi
+    let i+=1
+  done
+  return $ATLAS_NO
+}
+
+function getAtlasMemUsage
+{
+  ATLASMEM=0
+  local i=0
+  for bitmap in ${BITMAPS_G[@]}
+  do
+    if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
+    then
+      let ATLASMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $ATLASMEM
+}
+
+##################################global arrays manipulation
+#adds record to resource list
+#params: filename, bitmap, texture, state, size, size detail
+function addRecord
+{
+  if [ $# -ne 6 ]
+  then
+    error "addRecord - number of arguments is $#"
+  fi
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$2")
+  TEXTURES_G+=("$3")
+  STATES_G+=("$4")
+  SIZES_G+=("$5")
+  SIZE_DETAILS_G+=("$6")
+}
+
+#adds image resource to list
+#params: filename, bitmap, size, size detail
+function fileLoaded
+{
+  if [ $# -ne 4 ]
+  then
+    error "fileLoaded"
+  fi
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$2")
+  SIZES_G+=("$3")
+  SIZE_DETAILS_G+=("$4")
+  TEXTURES_G+=(0)
+  STATES_G+=(0)
+}
+
+#params: texture, size, size detail
+function atlasUploaded
+{
+  FILENAMES_G+=("-")
+  BITMAPS_G+=("$BITMAP_ID_ATLAS")
+  TEXTURES_G+=("$1")
+  STATES_G+=(2)
+  SIZES_G+=("$2")
+  SIZE_DETAILS_G+=("$3")
+}
+
+#params: size, size detail
+function frameBufUploaded
+{
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$BITMAP_ID_FB_TEXTURE")
+  TEXTURES_G+=("$2")
+  STATES_G+=(2)
+  SIZES_G+=("$3")
+  SIZE_DETAILS_G+=("$4")
+}
+
+
+##################################log parsing functions
+function checkLoaded
+{
+  if [[ "$1" =~ .*DALI.*[LOAD].*file\ (.*)\ to\ Bitmap\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local FILENAME="${BASH_REMATCH[1]}"
+    local BITMAP="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+
+    local found=0
+
+    #check if file was loaded before with same size
+    local i=0
+    if [ ${#FILENAMES_G[@]} -ne 0 ]
+    then
+
+    for filenameIter in ${FILENAMES_G[@]}
+    do
+      if [[ "$filenameIter" == "$FILENAME" ]]
+      then
+        if [[ ${SIZES_G[$i]} == "$SIZE" && ${SIZE_DETAILS_G[$i]} == "$SIZE_DETAILS" ]]
+        then
+          found=1
+          case ${STATES_G[$i]} in
+            0) #CPU
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            1) #CPUGPU
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            2) #GPU
+              STATES_G[$i]=1 #GPU->CPUGPU  loaded into memory again
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            3) #DISC
+              #previously discarded, load again
+              STATES_G[$i]=0
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            *)
+              error "checkLoaded - unknown state"
+              ;;
+          esac
+        else
+          #filename is same, but its loaded in different size
+          :
+        fi
+      fi
+      let i+=1
+    done
+    fi
+
+    if [ $found -ne 1 ]
+    then
+      fileLoaded "$FILENAME" "$BITMAP" "$SIZE" "$SIZE_DETAILS"
+    fi
+
+    return 0
+  else
+    error "checkLoaded"
+  fi
+}
+
+function checkUploaded
+{
+  if [[ "$1" =~ .*DALI.*[UPLOAD].*Bitmap\ (.*)\ to\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local BITMAP="${BASH_REMATCH[1]}"
+    local TEXTURE="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+
+    local i=0
+    local lastIdx=-1
+
+    if [[ "$BITMAP" =~ \(nil\) ]]
+    then
+      atlasUploaded $TEXTURE $SIZE "$SIZE_DETAILS"
+      return 0
+    else
+      #not a texture atlas
+      if [ ${#BITMAPS_G[@]} -ne $BITMAP_ID_ATLAS ]
+      then
+        for bitmap in ${BITMAPS_G[@]}
+        do
+          if [ $bitmap == $BITMAP ]
+          then
+            lastIdx=$i
+          fi
+        let i+=1
+        done
+      fi
+    fi
+
+    if [ $lastIdx != -1 ]
+    then
+      #Bitmap found
+      if [[ ${TEXTURES_G[$lastIdx]} == 0 && ${STATES_G[$lastIdx]} == 0 ]]
+      then
+        #File loaded in memory -> upload to GPU
+        TEXTURES_G[$lastIdx]="$TEXTURE"
+        STATES_G[$lastIdx]=1
+      elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
+      then
+        #BufferImage already in memory and GPU mem. -> updated
+        SIZES_G[$lastIdx]=$SIZE
+        SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
+      else
+        #bitmap uploaded to new texture
+        addRecord ${FILENAMES_G[$lastIdx]} $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
+      fi
+    else
+      #bitmapImage - not loaded from file
+      #newly added
+      addRecord "-" $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
+    fi
+    return 0
+  elif [[ "$1" =~ .*DALI.*[UPLOAD].*FrameBufferTexture\ (.*)\ GL\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local FBTEXTURE="${BASH_REMATCH[1]}"
+    local TEXTURE="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+    frameBufUploaded "$FBTEXTURE" "$TEXTURE" "$SIZE" "$SIZE_DETAILS"
+    return 0
+  else
+    echo "$1"
+    error "checkUploaded"
+  fi
+}
+
+function checkDeletedBuf
+{
+  if [[ "$1" =~ .*DALI.*[DELBUF].*Bitmap\ (.*)\ -\ .*size\ (.*) ]]
+  then
+    local BITMAP=${BASH_REMATCH[1]}
+    local i=0
+
+    for bitmap in ${BITMAPS_G[@]}
+    do
+      if [ $bitmap == "$BITMAP" ]
+      then
+        case ${STATES_G[$i]} in
+        0)
+            STATES_G[$i]=3 #CPU->DISC
+            ;;
+        1)
+            STATES_G[$i]=2 #CPUGPU->GPU
+            ;;
+        2)
+            #GPU->?
+            #probably previously freed bitmap buffer but memory is reused since
+            ;;
+        3)
+            #DISC->?
+            #probably previously freed but memory is reused since
+            ;;
+        *)
+            error "checkDeletedBuf - unkown state"
+            ;;
+        esac
+      fi
+    let i+=1
+    done
+
+    return 0
+  else
+    echo "$1"
+    error "checkDeletedBuf"
+  fi
+}
+
+function checkDeletedTexture
+{
+  if [[ "$1" =~ .*DALI.*[DELTEXTURE].*Texture\ (.*)\ -\ size\ (.*) ]]
+  then
+    local TEXTURE="${BASH_REMATCH[1]}"
+    local i=0
+    local lastIdx=-1
+
+    for texture in ${TEXTURES_G[@]}
+    do
+      if [ $texture == $TEXTURE ]
+      then
+        lastIdx=$i
+      fi
+    let i+=1
+    done
+
+    if [ $lastIdx != -1 ]
+    then
+      case ${STATES_G[$lastIdx]} in
+      0)
+          #CPU->?
+          echo "$1"
+          error "checkDeletedTexture - state CPU"
+          ;;
+      1)
+          STATES_G[$lastIdx]=0 #CPUGPU->CPU
+          ;;
+      2)
+          STATES_G[$lastIdx]=3 #GPU->DISC
+          ;;
+      3)
+          #DISC->?
+          echo "$1"
+          error "checkDeletedTexture - state DISC"
+          ;;
+      *)
+          error "checkDeletedTexture - unkown state"
+          ;;
+      esac
+    else
+      echo "$1"
+      error "checkDeletedTexture - texture not uploaded"
+    fi
+    return 0
+  else
+    echo "$1"
+    error "checkDeletedTexture"
+  fi
+}
+
+function processLine
+{
+  if [[ "$1" =~ .*DALI.*\ \[(.*)\].* ]]
+  then
+    RESCMD=${BASH_REMATCH[1]}
+    case "$RESCMD" in
+    LOAD)
+        checkLoaded "$1"
+        ;;
+    UPLOAD)
+        checkUploaded "$1"
+        ;;
+    DELBUF)
+        checkDeletedBuf "$1"
+        ;;
+    DELTEXTURE)
+        checkDeletedTexture "$1"
+        ;;
+    INIT)
+        ;;
+    FIN)
+        return 1 #end of last log session
+        ;;
+    *)
+        error "Unkown command $RESCMD"
+        ;;
+    esac
+  fi
+  return 0
+}
+
+function parseFile
+{
+  if [ -z "$1" ]
+  then
+    echo "ERROR in parseFile";
+    cleanup; exit 1
+  fi
+
+  #return if file does not contain dali resource log
+  if ! grep -q -m 1 -E "DALI.*\[INIT\]" $1
+  then
+    return 1
+  fi
+
+  #find last resource log session
+  local LOGBUFFER=$(sed -n 'H; /DALI.*\[INIT\]/h; ${g;p;}' $1)
+
+  while read -r line
+  do
+    #show PID of last process
+    PID_G=$(echo "$line" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
+    if [ ! -z "$PID_G" ]
+    then
+      break
+    fi
+  done <<< "$LOGBUFFER"
+
+  while read -r line
+  do
+    if ! processLine "$line" #stop parsing at the end of last session
+    then
+      break
+    fi
+  done <<< "$LOGBUFFER"
+}
+
+##################################draw and main functions
+function redraw
+{
+  tput cup 0 0 #move cursor to top left
+
+  # print info (4 lines)
+  tput bold
+  printLine "PID: $PID_G"
+  printLine "MEM 3D: $GPUMEM"
+  printLine "MEM Atlas: $ATLASMEM";
+  printLine "MEM CPU: $CPUMEM"
+  printLine "Number of atlases: $ATLAS_NO";
+  tput sgr0
+
+  # separator bar (colored bar with (actual/number of files) count)
+  tput cup $SEPARATOR_H 0
+  local PAGEIND="$(expr $CURPAGE + 1)/$(expr $MAXP + 1)"
+  local FILL_W=0
+  let FILL_W=$TERM_W-${#PAGEIND}
+  tput setab 4; printf $PAGEIND%"$FILL_W"s; printf '\n'; tput sgr0
+
+  # print filenames
+  local count=0
+  local index=0
+  let index=$CURPAGE*$MAXFILENO
+
+  filecount=${#FILENAMES_G[@]}
+
+  tput setaf 252
+
+  while [[ $count -lt $MAXFILENO ]]
+  do
+    if [[ $index -lt $filecount ]]
+    then
+      tput setab ${COLORS[${STATES_G[$index]}]}
+#     printPath "${FILENAMES_G[$count]}"
+      printLine "${FILENAMES_G[$index]} ${SIZES_G[$index]} ${SIZE_DETAILS_G[$index]}"
+    else
+      tput sgr0
+      printLine "" #clear remaining lines to fill screen
+    fi
+    let count+=1
+    let index+=1
+  done
+
+  # print keyboard shortcuts
+  tput setab 4; tput bold
+  IFS= printString "  |  n: next page  |  p: previous page  |  ^C: exit  |  Resource state: "
+  # print color codes
+  if [[ $TERM_W -gt 100 ]]
+  then
+    tput setab ${COLORS[0]}
+    echo -n " CPU "
+    tput setab ${COLORS[1]}
+    echo -n " CPUGPU "
+    tput setab ${COLORS[2]}
+    echo -n " GPU "
+    tput setab ${COLORS[3]}
+    echo -n " DISCARDED "
+  fi
+
+  tput sgr0
+}
+
+function readInput
+{
+    local key
+    read -n1 -t 0.3 key
+
+    case "$key" in
+        'p')
+            if [[ $CURPAGE -ne 0 ]]
+            then
+              let CURPAGE-=1
+            fi
+            ;;
+        'n')
+            if [[ $CURPAGE -lt $MAXP ]]
+            then
+              let CURPAGE+=1
+            fi
+            ;;
+    esac
+}
+
+function initVars
+{
+  FILENAMES_G=( )
+  BITMAPS_G=( )
+  TEXTURES_G=( )
+  SIZES_G=( )
+  SIZE_DETAILS_G=( )
+  STATES_G=( )
+}
+
+function cleanup
+{
+  tput cup 9999 0 #go to bottom of screen
+  tput cnorm #show cursor
+  tput sgr0
+  if [ -f "$DLOGTEMPFILE" ]
+  then
+    rm "$DLOGTEMPFILE"
+  fi
+}
+
+function update
+{
+  initVars
+  if [ -n "$USING_DLOG" ]
+  then
+    if [ -f "$DLOGTEMPFILE" ]
+    then
+      rm "$DLOGTEMPFILE"
+    fi
+    "$DLOGUTIL" DALI:I -d -f "$DLOGTEMPFILE" 2>/dev/null
+  fi
+
+  if [ ! -e "$INPUTFILE" ]
+  then
+    return 1
+  fi
+
+  parseFile "$INPUTFILE"
+
+  if [[ $? -gt 0 || ${#STATES_G[@]} -lt 1 ]]
+  then
+    return 1
+  fi
+
+  getCpuMemUsage
+  getGpuMemUsage
+  getAtlasMemUsage
+  getAtlasNumber
+
+  getTermSize
+  readInput
+  redraw
+}
+
+function main
+{
+  parseCmdLine $@
+
+  if [ -z "$INPUTFILE" ]
+  then
+    echo No input file specified;
+    cleanup
+    exit 1
+  fi
+
+  tput civis #hide cursor
+  tput clear #clear screen
+
+  echo "waiting for log..."
+
+  while [ 1 ]
+  do
+    update
+#    sleep 0.3  # we are now reading input for 0.3
+  done
+
+  cleanup
+}
+
+trap "cleanup; exit 0" SIGINT SIGTERM  #reset terminal when ^C is pressed
+# trap "getTermSize" SIGWINCH            #handle window resize
+
+main $@
diff --git a/adaptors/scripts/dalireslog.txt b/adaptors/scripts/dalireslog.txt
new file mode 100644 (file)
index 0000000..cce06af
--- /dev/null
@@ -0,0 +1,23 @@
+Resource log analyzer tool for dali applications
+
+USAGE:
+./dalireslog.sh [FILE]
+if FILE isn't specified script will try to use dlogutil
+
+Example:
+
+sh-4.1$ ./dalireslog.sh
+on a separate terminal:
+sh-4.1$ DALI_ENABLE_LOG=RESOURCE_LOG /opt/apps/com.samsung.dali-demo/bin/album.example
+
+Displayed information:
+3D        - amount of GPU memory used by application
+MEM Atlas - amount of GPU memory used by texture atlases. Usually this means font atlases.
+Number of atlases - how many texture atlases are present in memory
+
+A list of files is displayed in the main view, with different color codes representing different states.
+
+CPU       - resource is in memory, but hasn't been uploaded to a GL texture
+GPU       - resource has been uploaded to a GL texture, bitmap buffer discarded
+CPUGPU    - resource has been uploaded to a GL texture, but still present in CPU memory as well
+DISCARDED - resource has been discarded, memory freed up
diff --git a/adaptors/scripts/parse.rb b/adaptors/scripts/parse.rb
new file mode 100755 (executable)
index 0000000..ee34ea2
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env ruby
+# To use type parse.rb in the same folder as gl-abstraction.h
+# and pipe the output to a file
+#
+# Assemble the gl function call
+#
+# turns this: GLBoolean BlendEquation(GLEnum mode);
+#
+# into an inline function like this:
+#
+# GLBoolean BlendEquation(GLEnum mode)
+# {
+#    return glBlendEquation(mode);
+# }
+
+f = File.new("x11-gles.h")
+#scan each line in the file
+f.each do |x|
+
+  # x is original line, y is the new gl function call
+  y = String.new(x)
+
+  y.lstrip!                 # strip leading white spaces
+  returns = y.index("void"); # see if the function returns void
+  y.gsub!'void',' '          # delete the return types ...
+  y.gsub!(/GL[a-z]*/, '')    # remove GL types such as GLenum
+  y.gsub!('const','')        # remove const, *
+  y.gsub!('char','')         # remove char
+  y.gsub!('*','')            # remove pointer *
+  y.gsub!(/\s+/,"")          # remove all spaces
+  y.insert(0,'  gl')         # add gl to function name
+
+  if (returns != 0)          # insert a return if the function returns
+   y.lstrip!
+   y.insert(0,'  return ')
+  end
+
+  # print the function out
+  y << "\n"
+  x.lstrip!
+  x.gsub!(';','')
+  print x
+  print "{\n"
+  print y
+  print "}\n\n"
+end
+
+
+
diff --git a/adaptors/tizen/accessibility-adaptor-impl-tizen.cpp b/adaptors/tizen/accessibility-adaptor-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..dc9bf8d
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "accessibility-adaptor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/gesture-requests.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+#include <system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+// TODO: Update vconf-key.h ?
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return (bool)isEnabled;
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR" );
+#endif
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+BaseHandle Create()
+{
+  BaseHandle handle( AccessibilityAdaptor::Get() );
+
+  if ( !handle )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Dali::AccessibilityAdaptor adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() );
+      service.Register( typeid( adaptor ), adaptor );
+      handle = adaptor;
+    }
+  }
+
+  return handle;
+}
+TypeRegistration ACCESSIBILITY_ADAPTOR_TYPE( typeid(Dali::AccessibilityAdaptor), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return adaptor;
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return mReadPosition;
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  mActionHandler = &handler;
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  if( mAccessibilityGestureDetector )
+  {
+    mAccessibilityGestureDetector->SetGestureHandler(handler);
+  }
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->ClearAccessibilityFocus();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  bool ret = false;
+
+  // We always need to emit a scroll signal, whether it's only a hover or not,
+  // so always send the action to the action handler.
+  if( mActionHandler )
+  {
+    Dali::TouchEvent event(timeStamp);
+    event.points.push_back(point);
+    ret = mActionHandler->AccessibilityActionScroll( event );
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth) // hover event is ignored
+  {
+    // Process the touch event in accessibility gesture detector
+    if( mAccessibilityGestureDetector )
+    {
+      mAccessibilityGestureDetector->SendEvent(touchEvent);
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  bool ret = false;
+
+  Dali::TouchEvent touchEvent(timeStamp);
+  touchEvent.points.push_back(point);
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionTouch(touchEvent);
+  }
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionBack();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  EnableAccessibility();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  DisableAccessibility();
+}
+
+void AccessibilityAdaptor::EnableAccessibility()
+{
+  if(mIsEnabled == false)
+  {
+    mIsEnabled = true;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+  }
+}
+
+void AccessibilityAdaptor::DisableAccessibility()
+{
+  if(mIsEnabled == true)
+  {
+    mIsEnabled = false;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+
+    // Destroy the TtsPlayer if exists.
+    if ( Adaptor::IsAvailable() )
+    {
+      Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+      Adaptor& adaptorIpml = Adaptor::GetImplementation( adaptor );
+      adaptorIpml.DestroyTtsPlayer( Dali::TtsPlayer::SCREEN_READER );
+    }
+  }
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return mIsEnabled;
+}
+
+void AccessibilityAdaptor::SetIndicator(Indicator* indicator)
+{
+  mIndicator = indicator;
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+: mIsEnabled(false),
+  mReadPosition(0.0f, 0.0f),
+  mActionHandler(NULL),
+  mIndicator(NULL),
+  mIndicatorFocused(false)
+{
+  mIsEnabled = GetEnabledVConf();
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, mIsEnabled ? "ENABLED" : "DISABLED" );
+
+  vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, this );
+  vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, this );
+
+  mAccessibilityGestureDetector = new AccessibilityGestureDetector();
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tizen/adaptor-impl-tizen.cpp b/adaptors/tizen/adaptor-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..ff2468e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#ifdef OVER_TIZEN_SDK_2_2
+#include <app.h>
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void Adaptor::GetDataStoragePath( std::string& path)
+{
+  path = "";
+#ifdef OVER_TIZEN_SDK_2_2
+  char *pathInt = app_get_data_path();
+  if ( pathInt )
+  {
+    path = pathInt;
+    free( pathInt );
+  }
+#endif
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tizen/file.list b/adaptors/tizen/file.list
new file mode 100644 (file)
index 0000000..5a35d01
--- /dev/null
@@ -0,0 +1,12 @@
+# tizen
+
+adaptor_tizen_internal_src_files = \
+  $(adaptor_tizen_dir)/accessibility-adaptor-impl-tizen.cpp \
+  $(adaptor_tizen_dir)/adaptor-impl-tizen.cpp \
+  $(adaptor_tizen_dir)/framework-tizen.cpp \
+  $(adaptor_tizen_dir)/vsync-monitor-tizen.cpp \
+  $(adaptor_tizen_dir)/tilt-sensor-impl-tizen.cpp \
+  $(adaptor_tizen_dir)/tts-player-impl-tizen.cpp
+
+public_api_adaptor_tizen_header_files = \
+  $(adaptor_tizen_dir)/key-grab.h
diff --git a/adaptors/tizen/framework-tizen.cpp b/adaptors/tizen/framework-tizen.cpp
new file mode 100644 (file)
index 0000000..d764674
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "framework.h"
+
+// EXTERNAL INCLUDES
+#include <app.h>
+#include <bundle.h>
+#include <Ecore.h>
+
+#ifdef OVER_TIZEN_SDK_2_2
+#include <system_info.h>
+#include <app_control_internal.h>
+#include <bundle_internal.h>
+#endif
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <callback-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+/// Application Status Enum
+enum
+{
+  APP_CREATE,
+  APP_TERMINATE,
+  APP_PAUSE,
+  APP_RESUME,
+  APP_RESET,
+  APP_CONTROL,
+  APP_LANGUAGE_CHANGE,
+  APP_DEVICE_ROTATED,
+  APP_REGION_CHANGED,
+  APP_BATTERY_LOW,
+  APP_MEMORY_LOW
+};
+
+} // Unnamed namespace
+
+/**
+ * Impl to hide EFL data members
+ */
+struct Framework::Impl
+{
+  // Constructor
+
+  Impl(void* data)
+  : mAbortCallBack( NULL ),
+    mCallbackManager( NULL )
+  {
+    mEventCallback.create = AppCreate;
+    mEventCallback.terminate = AppTerminate;
+    mEventCallback.pause = AppPause;
+    mEventCallback.resume = AppResume;
+#ifndef OVER_TIZEN_SDK_2_2
+    mEventCallback.service = AppService;
+
+    mEventCallback.low_memory = NULL;
+    mEventCallback.low_battery = NULL;
+    mEventCallback.device_orientation = AppDeviceRotated;
+    mEventCallback.language_changed = AppLanguageChanged;
+    mEventCallback.region_format_changed = NULL;
+
+#else
+    mEventCallback.app_control = AppControl;
+
+    ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, AppDeviceRotated, data);
+    ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, AppLanguageChanged, data);
+    ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, AppRegionChanged, data);
+
+#endif
+
+    mCallbackManager = CallbackManager::New();
+  }
+
+  ~Impl()
+  {
+    delete mAbortCallBack;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+  }
+
+  // Data
+
+  CallbackBase* mAbortCallBack;
+  CallbackManager *mCallbackManager;
+
+#ifndef OVER_TIZEN_SDK_2_2
+  app_event_callback_s mEventCallback;
+#else
+  ui_app_lifecycle_callback_s mEventCallback;
+  app_event_handler_h handlers[5];
+#endif
+
+  /**
+   * Called by AppCore on application creation.
+   */
+  static bool AppCreate(void *data)
+  {
+    return static_cast<Framework*>(data)->AppStatusHandler(APP_CREATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application should terminate.
+   */
+  static void AppTerminate(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_TERMINATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is paused.
+   */
+  static void AppPause(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_PAUSE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is resumed.
+   */
+  static void AppResume(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_RESUME, NULL);
+  }
+
+  static void ProcessBundle(Framework* framework, bundle *bundleData)
+  {
+    if(bundleData == NULL)
+    {
+      return;
+    }
+
+    // get bundle name
+    char* bundleName = const_cast<char*>(bundle_get_val(bundleData, "name"));
+    if(bundleName != NULL)
+    {
+      framework->SetBundleName(bundleName);
+    }
+
+    // get bundle id
+    char* bundleId = const_cast<char*>(bundle_get_val(bundleData, "id"));
+    if(bundleId != NULL)
+    {
+      framework->SetBundleId(bundleId);
+    }
+  }
+
+#ifndef OVER_TIZEN_SDK_2_2
+  /**
+   * Called by AppCore when the application is launched from another module (e.g. homescreen).
+   * @param[in] b the bundle data which the launcher module sent
+   */
+  static void AppService(service_h service, void *data)
+  {
+    Framework* framework = static_cast<Framework*>(data);
+
+    if(framework == NULL)
+    {
+      return;
+    }
+    bundle *bundleData = NULL;
+
+    service_to_bundle(service, &bundleData);
+    ProcessBundle(framework, bundleData);
+
+    framework->AppStatusHandler(APP_RESET, NULL);
+  }
+
+  static void AppLanguageChanged(void* user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_LANGUAGE_CHANGE, NULL);
+  }
+
+  static void AppDeviceRotated(app_device_orientation_e orientation, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_DEVICE_ROTATED, NULL);
+  }
+
+#else
+
+  /**
+   * Called by AppCore when the application is launched from another module (e.g. homescreen).
+   * @param[in] b the bundle data which the launcher module sent
+   */
+  static void AppControl(app_control_h app_control, void *data)
+  {
+    Framework* framework = static_cast<Framework*>(data);
+    if(framework == NULL)
+    {
+      return;
+    }
+    bundle *bundleData = NULL;
+
+    app_control_to_bundle(app_control, &bundleData);
+    ProcessBundle(framework, bundleData);
+
+    framework->AppStatusHandler(APP_RESET, NULL);
+    framework->AppStatusHandler(APP_CONTROL, app_control);
+  }
+
+  static void AppLanguageChanged(app_event_info_h event_info, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_LANGUAGE_CHANGE, NULL);
+  }
+
+  static void AppDeviceRotated(app_event_info_h event_info, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_DEVICE_ROTATED, NULL);
+  }
+
+  static void AppRegionChanged(app_event_info_h event_info, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_REGION_CHANGED, NULL);
+  }
+
+  static void AppBatteryLow(app_event_info_h event_info, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_BATTERY_LOW, NULL);
+  }
+
+  static void AppMemoryLow(app_event_info_h event_info, void *user_data)
+  {
+    static_cast<Framework*>(user_data)->AppStatusHandler(APP_MEMORY_LOW, NULL);
+  }
+
+#endif
+
+private:
+  // Undefined
+  Impl( const Impl& impl );
+
+  // Undefined
+  Impl& operator=( const Impl& impl );
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv )
+: mObserver(observer),
+  mInitialised(false),
+  mRunning(false),
+  mArgc(argc),
+  mArgv(argv),
+  mBundleName(""),
+  mBundleId(""),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl(NULL)
+{
+
+#ifdef OVER_TIZEN_SDK_2_2
+  bool featureFlag = true;
+  system_info_get_platform_bool( "tizen.org/feature/opengles.version.2_0", &featureFlag );
+
+  if( featureFlag == false )
+  {
+    set_last_result( TIZEN_ERROR_NOT_SUPPORTED );
+    throw Dali::DaliException( "", "OpenGL ES 2.0 is not supported." );
+  }
+#endif
+
+  InitThreads();
+  mImpl = new Impl(this);
+}
+
+Framework::~Framework()
+{
+  if (mRunning)
+  {
+    Quit();
+  }
+
+  delete mImpl;
+}
+
+void Framework::Run()
+{
+  mRunning = true;
+
+#ifndef OVER_TIZEN_SDK_2_2
+  app_efl_main(mArgc, mArgv, &mImpl->mEventCallback, this);
+
+#else
+  int ret = ui_app_main(*mArgc, *mArgv, &mImpl->mEventCallback, this);
+  if (ret != APP_ERROR_NONE)
+  {
+    DALI_LOG_ERROR("Framework::Run(), ui_app_main() is failed. err = %d", ret);
+  }
+#endif
+
+  mRunning = false;
+}
+
+void Framework::Quit()
+{
+#ifndef OVER_TIZEN_SDK_2_2
+  app_efl_exit();
+#else
+  ui_app_exit();
+#endif
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if (mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void *bundleData)
+{
+  switch (type)
+  {
+    case APP_CREATE:
+    {
+      mInitialised = true;
+
+      // Connect to abnormal exit signals
+      mAbortHandler.AbortOnSignal( SIGINT );
+      mAbortHandler.AbortOnSignal( SIGQUIT );
+      mAbortHandler.AbortOnSignal( SIGKILL );
+      mAbortHandler.AbortOnSignal( SIGTERM );
+      mAbortHandler.AbortOnSignal( SIGHUP );
+
+      mObserver.OnInit();
+      break;
+    }
+
+    case APP_RESET:
+    {
+      mObserver.OnReset();
+      break;
+    }
+
+    case APP_RESUME:
+    {
+      mObserver.OnResume();
+      break;
+    }
+
+    case APP_TERMINATE:
+    {
+      mObserver.OnTerminate();
+      break;
+    }
+
+    case APP_PAUSE:
+    {
+      mObserver.OnPause();
+      break;
+    }
+
+    case APP_CONTROL:
+    {
+      mObserver.OnAppControl(bundleData);
+      break;
+    }
+
+    case APP_LANGUAGE_CHANGE:
+    {
+      mObserver.OnLanguageChanged();
+      break;
+    }
+
+    case APP_REGION_CHANGED:
+    {
+      mObserver.OnRegionChanged();
+      break;
+    }
+
+    case APP_BATTERY_LOW:
+    {
+      mObserver.OnBatteryLow();
+      break;
+    }
+
+    case APP_MEMORY_LOW:
+    {
+      mObserver.OnMemoryLow();
+      break;
+    }
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tizen/key-grab.h b/adaptors/tizen/key-grab.h
new file mode 100644 (file)
index 0000000..b697375
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef __DALI_KEY_GRAB_H__
+#define __DALI_KEY_GRAB_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include "key.h"
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+class Window;
+
+/**
+ * @brief Key grab functions.
+ * @since_tizen 2.4
+ */
+namespace KeyGrab
+{
+
+/**
+ * @brief Grabs the key specfied by @a key for @a window only when @a window is the topmost window.
+ *
+ * This function can be used for following example scenarios:
+ * - Mobile - Using volume up/down as zoom up/down in camera apps.
+ *
+ * @since_tizen 2.4
+ * @param[in] window The window to set
+ * @param[in] dailKey The key code to grab (defined in key.h)
+ * @return true if the grab succeeds.
+ */
+DALI_IMPORT_API bool GrabKeyTopmost( Window window, Dali::KEY daliKey );
+
+/**
+ * @brief Ungrabs the key specfied by @a key for @a window.
+ *
+ * @since_tizen 2.4
+ * @param[in] window The window to set
+ * @param[in] dailKey The key code to ungrab (defined in key.h)
+ * @return true if the ungrab succeeds.
+ */
+DALI_IMPORT_API bool UngrabKeyTopmost( Window window, Dali::KEY daliKey );
+
+/**
+ * @brief Key grab mode for platform-level APIs.
+ * @since_tizen 2.4
+ */
+enum KeyGrabMode
+{
+  TOPMOST = 0,             ///< Grab a key only when on the top of the grabbing-window stack mode.
+  SHARED,                  ///< Grab a key together with the other client window(s) mode.
+  OVERRIDE_EXCLUSIVE,      ///< Grab a key exclusively regardless of the grabbing-window's position on the window stack with the possibility of overriding the grab by the other client window mode.
+  EXCLUSIVE                ///< Grab a key exclusively regardless of the grabbing-window's position on the window stack mode.
+};
+
+/**
+ * @platform
+ * @brief Grabs the key specfied by @a key for @a window in @a grabMode.
+ *
+ * @details This function can be used for following example scenarios:
+ * - TV - A user might want to change the volume or channel of the background TV contents while focusing on the foregrund app.
+ * - Mobile - When a user presses Home key, the homescreen appears regardless of current foreground app.
+ * - Mobile - Using volume up/down as zoom up/down in camera apps.
+ *
+ * @since_tizen 2.4
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/keygrab
+ * @param[in] window The window to set
+ * @param[in] dailKey The key code to grab (defined in key.h)
+ * @param[in] grabMode The grab mode for the key
+ * @return true if the grab succeeds.
+ */
+DALI_IMPORT_API bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode );
+
+/**
+ * @platform
+ * @brief Ungrabs the key specfied by @a key for @a window.
+ *
+ * @since_tizen 2.4
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/keygrab
+ * @param[in] window The window to set
+ * @param[in] dailKey The key code to ungrab (defined in key.h)
+ * @return true if the ungrab succeeds.
+ */
+DALI_IMPORT_API bool UngrabKey( Window window, Dali::KEY daliKey );
+
+} // namespace KeyGrab
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_KEY_GRAB_H__
diff --git a/adaptors/tizen/tilt-sensor-impl-tizen.cpp b/adaptors/tizen/tilt-sensor-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..058abf4
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tilt-sensor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+#ifdef SENSOR_ENABLED
+#include <sensor_internal.h>
+#endif
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace // unnamed namespace
+{
+
+const char* const SIGNAL_TILTED = "tilted";
+
+const int NUMBER_OF_SAMPLES = 10;
+
+const float MAX_ACCELEROMETER_XY_VALUE = 9.8f;
+
+// Type Registration
+Dali::BaseHandle GetInstance()
+{
+  return Dali::Internal::Adaptor::TiltSensor::Get();
+}
+
+Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), GetInstance );
+
+Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::TiltSensor TiltSensor::New()
+{
+  Dali::TiltSensor sensor = Dali::TiltSensor(new TiltSensor());
+
+  return sensor;
+}
+
+Dali::TiltSensor TiltSensor::Get()
+{
+  Dali::TiltSensor sensor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the keyboard focus manager is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TiltSensor ) );
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to keyboard focus manager
+      sensor = Dali::TiltSensor( dynamic_cast< TiltSensor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      // Create a singleton instance
+      sensor = TiltSensor::New();
+      service.Register( typeid( sensor ), sensor );
+      handle = sensor;
+    }
+  }
+
+  return sensor;
+}
+
+TiltSensor::~TiltSensor()
+{
+  Disable();
+}
+
+bool TiltSensor::Enable()
+{
+  // Make sure sensor API is responding
+  bool success = Update();
+
+  if ( success )
+  {
+    if ( !mTimer )
+    {
+      mTimer = Dali::Timer::New( 1000.0f / mFrequencyHertz );
+      mTimer.TickSignal().Connect( mTimerSlot, &TiltSensor::Update );
+    }
+
+    if ( mTimer &&
+         !mTimer.IsRunning() )
+    {
+      mTimer.Start();
+    }
+  }
+
+  return success;
+}
+
+void TiltSensor::Disable()
+{
+  if ( mTimer )
+  {
+    mTimer.Stop();
+    mTimer.Reset();
+  }
+}
+
+bool TiltSensor::IsEnabled() const
+{
+  return ( mTimer && mTimer.IsRunning() );
+}
+
+float TiltSensor::GetRoll() const
+{
+  return mRoll;
+}
+
+float TiltSensor::GetPitch() const
+{
+  return mPitch;
+}
+
+Quaternion TiltSensor::GetRotation() const
+{
+  return mRotation;
+}
+
+TiltSensor::TiltedSignalType& TiltSensor::TiltedSignal()
+{
+  return mTiltedSignal;
+}
+
+void TiltSensor::SetUpdateFrequency( float frequencyHertz )
+{
+  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );
+
+  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
+  {
+    mFrequencyHertz = frequencyHertz;
+
+    if ( mTimer )
+    {
+      mTimer.SetInterval( 1000.0f / mFrequencyHertz );
+    }
+  }
+}
+
+float TiltSensor::GetUpdateFrequency() const
+{
+  return mFrequencyHertz;
+}
+
+void TiltSensor::SetRotationThreshold(Radian rotationThreshold)
+{
+  mRotationThreshold = rotationThreshold;
+}
+
+Radian TiltSensor::GetRotationThreshold() const
+{
+  return mRotationThreshold;
+}
+
+bool TiltSensor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );
+
+  if( sensor && ( SIGNAL_TILTED == signalName ) )
+  {
+    sensor->TiltedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+TiltSensor::TiltSensor()
+: mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
+  mTimerSlot( this ),
+  mSensorFrameworkHandle( -1 ),
+  mRoll( 0.0f ),
+  mPitch( 0.0f ),
+  mRotation( Radian( 0.0f), Vector3::YAXIS ),
+  mRotationThreshold( 0.0f )
+{
+  mRollValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+  mPitchValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+}
+
+bool TiltSensor::Update()
+{
+  float newRoll = 0.0f;
+  float newPitch = 0.0f;
+  Quaternion newRotation;
+#ifdef SENSOR_ENABLED
+
+  // Read accelerometer data
+
+  mSensorFrameworkHandle = sf_connect( ACCELEROMETER_SENSOR );
+  if ( mSensorFrameworkHandle < 0 )
+  {
+    DALI_LOG_ERROR( "Failed to connect to sensor framework" );
+    return false;
+  }
+
+  if ( sf_start(mSensorFrameworkHandle, 0) < 0 )
+  {
+    DALI_LOG_ERROR( "Failed to start sensor" );
+    sf_disconnect(mSensorFrameworkHandle);
+    return false;
+  }
+
+  sensor_data_t* base_data_values = (sensor_data_t*)malloc(sizeof(sensor_data_t));
+
+  int dataErr = sf_get_data(mSensorFrameworkHandle, ACCELEROMETER_BASE_DATA_SET, base_data_values);
+  if ( dataErr < 0 )
+  {
+    DALI_LOG_ERROR( "Failed to retrieve sensor data" );
+    free(base_data_values);
+    sf_stop(mSensorFrameworkHandle);
+    sf_disconnect(mSensorFrameworkHandle);
+    return false;
+  }
+
+  sf_stop(mSensorFrameworkHandle);
+  sf_disconnect(mSensorFrameworkHandle);
+
+  mRollValues.push_back( base_data_values->values[0] );
+  mRollValues.pop_front();
+
+  mPitchValues.push_back( base_data_values->values[1] );
+  mPitchValues.pop_front();
+
+  free(base_data_values);
+  base_data_values = NULL;
+
+  float averageRoll( 0.0f );
+  for ( std::deque<float>::const_iterator iter = mRollValues.begin(); mRollValues.end() != iter; ++iter )
+  {
+    averageRoll += *iter;
+  }
+  averageRoll /= mRollValues.size();
+
+  float averagePitch( 0.0f );
+  for ( std::deque<float>::const_iterator iter = mPitchValues.begin(); mPitchValues.end() != iter; ++iter )
+  {
+    averagePitch += *iter;
+  }
+  averagePitch /= mPitchValues.size();
+
+  newRoll  = Clamp( float(averageRoll  / MAX_ACCELEROMETER_XY_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
+  newPitch = Clamp( float(averagePitch / MAX_ACCELEROMETER_XY_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
+
+  newRotation = Quaternion( Radian( newRoll  * Math::PI * -0.5f ), Vector3::YAXIS ) *
+                Quaternion( Radian( newPitch * Math::PI * -0.5f ), Vector3::XAXIS );
+#endif // SENSOR_ENABLED
+
+  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));
+  // If the change in value is more than the threshold then emit tilted signal.
+  if( angle > mRotationThreshold )
+  {
+    mRoll = newRoll;
+    mPitch = newPitch;
+    mRotation = newRotation;
+
+    if ( !mTiltedSignal.Empty() )
+    {
+      Dali::TiltSensor handle( this );
+      mTiltedSignal.Emit( handle );
+    }
+  }
+
+  return true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tizen/tilt-sensor-impl.h b/adaptors/tizen/tilt-sensor-impl.h
new file mode 100644 (file)
index 0000000..4f864ad
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
+#define __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <deque>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <tilt-sensor.h>
+#include <timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ */
+class TiltSensor : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::TiltSensor::TiltedSignalType TiltedSignalType;
+
+  /**
+   * Create a TiltSensor.
+   * This should only be called once by the Adaptor class.
+   * @return A newly allocated tilt-sensor.
+   */
+  static Dali::TiltSensor New();
+
+  /**
+   * @copydoc Dali::TiltSensor::Get()
+   */
+  static Dali::TiltSensor Get();
+
+  /**
+   * @copydoc Dali::TiltSensor::Enable()
+   */
+  bool Enable();
+
+  /**
+   * @copydoc Dali::TiltSensor::Disable()
+   */
+  void Disable();
+
+  /**
+   * @copydoc Dali::TiltSensor::IsEnabled()
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRoll()
+   */
+  float GetRoll() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetPitch()
+   */
+  float GetPitch() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotation()
+   */
+  Quaternion GetRotation() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::TiltedSignal()
+   */
+  TiltedSignalType& TiltedSignal();
+
+  /**
+   * @copydoc Dali::TiltSensor::SetUpdateFrequency()
+   */
+  void SetUpdateFrequency( float frequencyHertz );
+
+  /**
+   * @copydoc Dali::TiltSensor::GetUpdateFrequency()
+   */
+  float GetUpdateFrequency() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetRotationThreshold()
+   */
+  void SetRotationThreshold(Radian rotationThreshold);
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotationThreshold()
+   */
+  Radian GetRotationThreshold() const;
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * Private constructor; see also TiltSensor::New()
+   */
+  TiltSensor();
+
+  /**
+   * Destructor
+   */
+  virtual ~TiltSensor();
+
+  /**
+   * Timer callback to update the tilt values
+   */
+  bool Update();
+
+  // Undefined
+  TiltSensor(const TiltSensor&);
+
+  // Undefined
+  TiltSensor& operator=(TiltSensor&);
+
+private:
+
+  float mFrequencyHertz;
+  Dali::Timer mTimer;
+  SlotDelegate< TiltSensor > mTimerSlot;
+
+  int mSensorFrameworkHandle;
+
+  float mRoll;
+  float mPitch;
+  Quaternion mRotation;
+
+  Radian mRotationThreshold;
+
+  std::deque<float> mRollValues;
+  std::deque<float> mPitchValues;
+
+  TiltedSignalType mTiltedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::TiltSensor& GetImplementation(Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TiltSensor&>(handle);
+}
+
+inline const Internal::Adaptor::TiltSensor& GetImplementation(const Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  const BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TiltSensor&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
diff --git a/adaptors/tizen/tts-player-impl-tizen.cpp b/adaptors/tizen/tts-player-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..976602e
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tts-player-impl.h"
+
+// EXTERNAL INCLUDES
+#include <tts.h>
+#include <stdio.h>
+
+#include <dali/public-api/object/type-registry.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return Dali::TtsPlayer::Get() ;
+}
+
+Dali::TypeRegistration mType( typeid(Dali::TtsPlayer), typeid(Dali::BaseHandle), Create );
+
+/**
+ * Helper function to convert Tizen-specific TTS state to external state.
+ * @param state The Tizen TTS state.
+ * @return The external TTS state.
+ */
+Dali::TtsPlayer::State InternalToExternalState( tts_state_e state )
+{
+  switch( state )
+  {
+    case TTS_STATE_CREATED:
+    {
+      return Dali::TtsPlayer::UNAVAILABLE;
+    }
+    case TTS_STATE_READY:
+    {
+      return Dali::TtsPlayer::READY;
+    }
+    case TTS_STATE_PLAYING:
+    {
+      return Dali::TtsPlayer::PLAYING;
+    }
+    case TTS_STATE_PAUSED:
+    {
+      return Dali::TtsPlayer::PAUSED;
+    }
+  }
+
+  return Dali::TtsPlayer::UNAVAILABLE;
+}
+
+} // unnamed namespace
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* TtsPlayer::gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TTS_PLAYER");
+#endif
+
+Dali::TtsPlayer TtsPlayer::New(Dali::TtsPlayer::Mode mode)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer(new TtsPlayer(mode));
+
+  return player;
+}
+
+TtsPlayer::TtsPlayer(Dali::TtsPlayer::Mode mode)
+: mInitialized(false),
+  mUnplayedString(""),
+  mUtteranceId(0),
+  mTtsMode(mode)
+{
+  Initialize();
+}
+
+TtsPlayer::~TtsPlayer()
+{
+  // If it is playing, stop it
+  Stop();
+
+  // Unset the callback funtion for TTS state change
+  int retVal = tts_unset_state_changed_cb(mTtsHandle);
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+
+  // Destroy the TTS handle and disconnects the daemon
+  retVal = tts_destroy(mTtsHandle);
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+}
+
+void TtsPlayer::Initialize()
+{
+  // Create the TTS handle
+  int retVal = tts_create(&mTtsHandle);
+
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+  else
+  {
+    // Set the callback funtion for TTS state change
+    retVal = tts_set_state_changed_cb(mTtsHandle, &StateChangedCallback, this);
+    if( retVal != TTS_ERROR_NONE )
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+
+    // Check tts mode
+    tts_mode_e ttsMode = TTS_MODE_DEFAULT;
+    switch (mTtsMode)
+    {
+      case Dali::TtsPlayer::DEFAULT:
+        ttsMode = TTS_MODE_DEFAULT;
+      break;
+      case Dali::TtsPlayer::NOTIFICATION:
+        ttsMode = TTS_MODE_NOTIFICATION;
+      break;
+      case Dali::TtsPlayer::SCREEN_READER:
+        ttsMode = TTS_MODE_SCREEN_READER;
+      break;
+      default:
+      break;
+    }
+
+    // Set mode
+    retVal = tts_set_mode(mTtsHandle, ttsMode);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+
+    // Connect the TTS daemon asynchronously
+    retVal = tts_prepare(mTtsHandle);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+  }
+}
+
+void TtsPlayer::Play(const std::string& text)
+{
+  if(mInitialized)
+  {
+    Stop();
+
+    // Add text to the queue, and use normal speed, default language and default voice set by the user
+    int retVal = tts_add_text(mTtsHandle, text.c_str(), NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &mUtteranceId);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else
+    {
+      // Start synthesizing voice from text in the queue and play synthesized audio data
+      retVal = tts_play(mTtsHandle);
+      if(retVal != TTS_ERROR_NONE)
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+  else
+  {
+    mUnplayedString = text;
+  }
+}
+
+void TtsPlayer::Stop()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PLAYING || state == TTS_STATE_PAUSED)
+    {
+      // If it is playing or paused, stop playing and clear the queue
+      retVal = tts_stop(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+void TtsPlayer::Pause()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PLAYING)
+    {
+      // If the player is playing, pause it.
+      retVal = tts_pause(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+void TtsPlayer::Resume()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PAUSED)
+    {
+      // If the player is paused, resume it.
+      retVal = tts_play(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+Dali::TtsPlayer::State TtsPlayer::GetState()
+{
+  Dali::TtsPlayer::State ttsState = Dali::TtsPlayer::UNAVAILABLE;
+
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else
+    {
+      ttsState = InternalToExternalState( state );
+    }
+  }
+
+  return ttsState;
+}
+
+Dali::TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  return mStateChangedSignal;
+}
+
+void TtsPlayer::EmitStateChangedSignal( tts_state_e previous, tts_state_e current )
+{
+  // Convert the previous and current states to external states and emit them as a signal.
+  if( !mStateChangedSignal.Empty() )
+  {
+    mStateChangedSignal.Emit( InternalToExternalState( previous ), InternalToExternalState( current ) );
+  }
+}
+
+void TtsPlayer::StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void *userData)
+{
+  // Get the implementation (this is a static function).
+  TtsPlayer* obj = static_cast<TtsPlayer*>(userData);
+
+  // Emit the signal.
+  obj->EmitStateChangedSignal( previous, current );
+
+  if(!obj->mInitialized && current == TTS_STATE_READY)
+  {
+    obj->mInitialized = true;
+
+    // if there is queued text before initialization, play it
+    if(obj->mUnplayedString != "")
+    {
+      obj->Play(obj->mUnplayedString);
+      obj->mUnplayedString = "";
+    }
+  }
+}
+
+void TtsPlayer::LogErrorCode(tts_error_e reason)
+{
+  std::string error_string;
+
+  switch (reason)
+  {
+    case TTS_ERROR_NONE:
+    {
+      break;
+    }
+    case TTS_ERROR_OUT_OF_MEMORY:
+    {
+      error_string = "TTS: Out of Memory\n";
+      break;
+    }
+    case TTS_ERROR_IO_ERROR:
+    {
+      error_string = "TTS: I/O error\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_PARAMETER:
+    {
+      error_string = "TTS: Invalid parameter\n";
+      break;
+    }
+    case TTS_ERROR_OUT_OF_NETWORK:
+    {
+      error_string = "TTS: Out of network\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_STATE:
+    {
+      error_string = "TTS: Invalid state\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_VOICE:
+    {
+      error_string = "TTS: Invalid voice\n";
+      break;
+    }
+    case TTS_ERROR_ENGINE_NOT_FOUND:
+    {
+      error_string = "TTS: No available engine\n";
+      break;
+    }
+    case TTS_ERROR_TIMED_OUT:
+    {
+      error_string = "TTS: No answer from the daemon\n";
+      break;
+    }
+    case TTS_ERROR_OPERATION_FAILED:
+    {
+      error_string = "TTS: Operation failed\n";
+      break;
+    }
+    default:
+    {
+      error_string = "Invalid TTS error code\n";
+      break;
+    }
+  }
+
+  if(reason != TTS_ERROR_NONE)
+  {
+    DALI_LOG_WARNING("[%s:%d] tts error : %s\n", __FUNCTION__, __LINE__, error_string.c_str());
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tizen/tts-player-impl.h b/adaptors/tizen/tts-player-impl.h
new file mode 100644 (file)
index 0000000..15462dd
--- /dev/null
@@ -0,0 +1,175 @@
+#ifndef __DALI_INTERNAL_TTS_PLAYER_H__
+#define __DALI_INTERNAL_TTS_PLAYER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <tts.h>
+#include <string>
+
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <tts-player.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Text-to-speech player
+ */
+class TtsPlayer : public Dali::BaseObject
+{
+
+public:
+
+  /**
+   * Create a TtsPlayer with the given mode.
+   * This should only be called once by the Adaptor class for each given mode.
+   * @param mode the mode of tts-player
+   * @return A newly created TtsPlayer.
+   */
+  static Dali::TtsPlayer New(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc TtsPlayer::Play()
+   */
+  void Play(const std::string& text);
+
+  /**
+   * @copydoc TtsPlayer::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc TtsPlayer::Pause()
+   */
+  void Pause();
+
+  /**
+   * @copydoc TtsPlayer::Resume()
+   */
+  void Resume();
+
+  /**
+   * @copydoc TtsPlayer::GetState()
+   */
+  Dali::TtsPlayer::State GetState();
+
+  /**
+   * @copydoc TtsPlayer::StateChangedSignal()
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal();
+
+private:
+
+  /**
+   * Private Constructor; see also TtsPlayer::New()
+   * @param mode the mode of tts-player
+   */
+  TtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * Destructor
+   */
+  virtual ~TtsPlayer();
+
+  /**
+   * Initializes the player.
+   */
+  void Initialize();
+
+  /**
+   * Logs the error code.
+   * @param[in] reason The error code
+   */
+  void LogErrorCode(tts_error_e reason);
+
+  /**
+   * Used to emit the state changed signal from outside the object (EG. A static function).
+   * @param[in] previous The previous state
+   * @param[in] current The current state
+   */
+  void EmitStateChangedSignal( tts_state_e previous, tts_state_e current );
+
+  /**
+   * Called when the state of TTS is changed.
+   *
+   * @param[in] tts The handle for TTS
+   * @param[in] previous A previous state
+   * @param[in] current A current state
+   * @param[in] userData The user data passed from the callback registration function.
+   */
+  static void StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void *userData);
+
+  // Undefined
+  TtsPlayer(const TtsPlayer&);
+
+  // Undefined
+  TtsPlayer& operator=(TtsPlayer&);
+
+private:
+
+  Dali::TtsPlayer::StateChangedSignalType mStateChangedSignal; ///< Signal emitted when the TTS state changes
+  bool mInitialized; ///< Whether the TTS player is initialised successfully or not
+  std::string mUnplayedString; ///< The text that can not be played because tts engine is not yet initialized
+  tts_h mTtsHandle;  ///< The handle of TTS
+  int mUtteranceId;  ///< The utterance ID
+
+  Dali::TtsPlayer::Mode mTtsMode; ///< The current mode of tts engine
+
+#if defined(DEBUG_ENABLED)
+public:
+  static Debug::Filter* gLogFilter;
+#endif
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::TtsPlayer& GetImplementation(Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::TtsPlayer& GetImplementation(const Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TTS_PLAYER_H__
diff --git a/adaptors/tizen/vsync-monitor-tizen.cpp b/adaptors/tizen/vsync-monitor-tizen.cpp
new file mode 100644 (file)
index 0000000..2f89812
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include "vsync-monitor.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
+const unsigned int TRUE = 1u;
+const unsigned int FALSE = 0u;
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VSYNC_MONITOR");
+#endif
+
+const char * const DRM_DEVICE( "/dev/dri/card0" );
+const int FD_NONE( -1 );
+
+void ScreenStatusChanged(keynode_t* node, void* data)
+{
+  VSyncMonitor* vsyncMonitor( static_cast< VSyncMonitor* >( data ) );
+
+  int status = 0;
+  vconf_get_int( VCONFKEY_PM_STATE, &status );
+
+  // status values
+  //  - VCONFKEY_PM_STATE_NORMAL : turn vsync on
+  //  - VCONFKEY_PM_STATE_LCDDIM : turn vsync off
+  //  - VCONFKEY_PM_STATE_LCDOFF : turn vsync off
+  //  - VCONFKEY_PM_STATE_SLEEP : turn vsync off
+  const unsigned int screenOn( VCONFKEY_PM_STATE_NORMAL == status );
+
+  vsyncMonitor->SetHardwareVSyncAvailable( screenOn );
+
+  DALI_LOG_INFO( gLogFilter, Debug::Concise, "%s, Screen %s.\n", __PRETTY_FUNCTION__, screenOn ? "On" : "Off" );
+}
+
+} // unnamed namespace
+
+VSyncMonitor::VSyncMonitor()
+: mFileDescriptor( FD_NONE ),
+  mUseHardwareVSync( TRUE ),
+  mHardwareVSyncAvailable( FALSE )
+{
+  vconf_notify_key_changed( VCONFKEY_PM_STATE, ScreenStatusChanged, this );
+}
+
+VSyncMonitor::~VSyncMonitor()
+{
+  Terminate();
+
+  vconf_ignore_key_changed( VCONFKEY_PM_STATE, ScreenStatusChanged );
+}
+
+void VSyncMonitor::SetUseHardwareVSync( bool useHardware )
+{
+  mUseHardwareVSync = useHardware;
+}
+
+void VSyncMonitor::SetHardwareVSyncAvailable( bool hardwareVSyncAvailable )
+{
+  mHardwareVSyncAvailable = hardwareVSyncAvailable;
+}
+
+void VSyncMonitor::Initialize()
+{
+  DALI_ASSERT_DEBUG( mFileDescriptor == FD_NONE && "VSyncMonitor::Initialize() called twice" );
+
+  // Read initial 'use hardware' status
+  ScreenStatusChanged( NULL, this );
+
+  // open /dev node
+  mFileDescriptor = open( DRM_DEVICE, O_RDWR );
+
+  // setup vblank request - block and wait for next vblank
+  mVBlankInfo.request.type = DRM_VBLANK_NEXTONMISS;
+  mVBlankInfo.request.sequence = 0;
+  mVBlankInfo.request.signal = 0;
+
+  // setup vblank reply - block and wait for next vblank
+  mVBlankInfo.reply.type = DRM_VBLANK_NEXTONMISS;
+  mVBlankInfo.reply.sequence = 0;
+  mVBlankInfo.reply.tval_sec = 0;
+  mVBlankInfo.reply.tval_usec = 0;
+}
+
+void VSyncMonitor::Terminate()
+{
+  if( mFileDescriptor != FD_NONE )
+  {
+    close( mFileDescriptor );
+    mFileDescriptor = FD_NONE;
+  }
+}
+
+bool VSyncMonitor::UseHardware()
+{
+  return mUseHardwareVSync && mHardwareVSyncAvailable && (FD_NONE != mFileDescriptor );
+}
+
+bool VSyncMonitor::DoSync( unsigned int& frameNumber, unsigned int& seconds, unsigned int& microseconds )
+{
+  DALI_ASSERT_DEBUG( mFileDescriptor != FD_NONE && "ECoreX::VSyncMonitor is not initialized" );
+
+  if( 0 == drmWaitVBlank( mFileDescriptor, &mVBlankInfo ) )
+  {
+    frameNumber = mVBlankInfo.reply.sequence;
+    seconds = mVBlankInfo.reply.tval_sec;
+    microseconds = mVBlankInfo.reply.tval_usec;
+
+    return true;
+  }
+
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tv/file.list b/adaptors/tv/file.list
new file mode 100644 (file)
index 0000000..17f3e8d
--- /dev/null
@@ -0,0 +1,8 @@
+# tv profile internal files
+adaptor_common_internal_tv_profile_src_files = \
+  $(adaptor_tv_dir)/tv-render-surface-factory.cpp \
+  $(adaptor_tv_dir)/tv-system-settings.cpp \
+  $(adaptor_tv_dir)/tv-color-controller-impl.cpp
+
+adaptor_x11_internal_tv_profile_key_src_files = \
+  $(adaptor_tv_dir)/key-mapping-tv.cpp
diff --git a/adaptors/tv/key-mapping-tv.cpp b/adaptors/tv/key-mapping-tv.cpp
new file mode 100644 (file)
index 0000000..6c9012f
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "key-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,          false },
+  { "Menu",                  DALI_KEY_MENU,            false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,      false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,     false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable))/ (sizeof(KeyLookup));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tv/tv-color-controller-impl.cpp b/adaptors/tv/tv-color-controller-impl.cpp
new file mode 100644 (file)
index 0000000..ec9c100
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <common/color-controller-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::ColorController ColorController::Get()
+{
+  Dali::ColorController colorController;
+  return colorController;
+}
+
+ColorController::ColorController()
+{
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return false;
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/tv/tv-render-surface-factory.cpp b/adaptors/tv/tv-render-surface-factory.cpp
new file mode 100644 (file)
index 0000000..802810f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <pixmap-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+DALI_EXPORT_API PixmapRenderSurface* CreatePixmapSurface(
+  PositionSize       positionSize,
+  Any                surface,
+  const std::string& name,
+  bool               isTransparent )
+{
+  return new PixmapRenderSurface( positionSize, surface, name, isTransparent );
+}
+
+} // namespace ECoreX
+
+} // namespace Dali
+
+
+
diff --git a/adaptors/tv/tv-system-settings.cpp b/adaptors/tv/tv-system-settings.cpp
new file mode 100644 (file)
index 0000000..e87731a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <system_settings.h>
+#include <Elementary.h>
+
+// INTERNAL INCLUDES
+#include <system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/accessibility-adaptor-impl-ubuntu.cpp b/adaptors/ubuntu/accessibility-adaptor-impl-ubuntu.cpp
new file mode 100644 (file)
index 0000000..a5a29ab
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "accessibility-adaptor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/gesture-requests.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+#include "system-settings.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+
+BaseHandle Create()
+{
+  BaseHandle handle( AccessibilityAdaptor::Get() );
+
+  if ( !handle )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Dali::AccessibilityAdaptor adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() );
+      service.Register( typeid( adaptor ), adaptor );
+      handle = adaptor;
+    }
+  }
+
+  return handle;
+}
+TypeRegistration ACCESSIBILITY_ADAPTOR_TYPE( typeid(Dali::AccessibilityAdaptor), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return adaptor;
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return mReadPosition;
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  mActionHandler = &handler;
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  if( mAccessibilityGestureDetector )
+  {
+    mAccessibilityGestureDetector->SetGestureHandler(handler);
+  }
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->ClearAccessibilityFocus();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  bool ret = false;
+
+  // We always need to emit a scroll signal, whether it's only a hover or not,
+  // so always send the action to the action handler.
+  if( mActionHandler )
+  {
+    Dali::TouchEvent event(timeStamp);
+    event.points.push_back(point);
+    ret = mActionHandler->AccessibilityActionScroll( event );
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if( type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth ) // hover event is ignored
+  {
+    // Process the touch event in accessibility gesture detector
+    if( mAccessibilityGestureDetector )
+    {
+      mAccessibilityGestureDetector->SendEvent( touchEvent );
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  bool ret = false;
+
+  Dali::TouchEvent touchEvent(timeStamp);
+  touchEvent.points.push_back(point);
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionTouch(touchEvent);
+  }
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionBack();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  EnableAccessibility();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  DisableAccessibility();
+}
+
+void AccessibilityAdaptor::EnableAccessibility()
+{
+  if(mIsEnabled == false)
+  {
+    mIsEnabled = true;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+  }
+}
+
+void AccessibilityAdaptor::DisableAccessibility()
+{
+  if(mIsEnabled == true)
+  {
+    mIsEnabled = false;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+
+    // Destroy the TtsPlayer if exists.
+    if ( Adaptor::IsAvailable() )
+    {
+      Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+      Adaptor::GetImplementation( adaptor ).DestroyTtsPlayer( Dali::TtsPlayer::SCREEN_READER );
+    }
+  }
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return mIsEnabled;
+}
+
+void AccessibilityAdaptor::SetIndicator(Indicator* indicator)
+{
+  mIndicator = indicator;
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+: mIsEnabled(false),
+  mActionHandler(NULL),
+  mIndicator(NULL),
+  mIndicatorFocused(false)
+{
+  int isEnabled = 0;
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled?"ENABLED":"DISABLED");
+
+  if(isEnabled == 1)
+  {
+    mIsEnabled = true;
+  }
+  else
+  {
+    mIsEnabled = false;
+  }
+
+  mAccessibilityGestureDetector = new AccessibilityGestureDetector();
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  bool indicatorFocused = false;
+
+  // Check whether the Indicator is focused
+  if( mIndicator && mIndicator->IsConnected() )
+  {
+    // Check the position and size of Indicator actor
+    Dali::Actor indicatorActor = mIndicator->GetActor();
+    Vector3 position = Vector3(0.0f, 0.0f, 0.0f);
+    Vector3 size = indicatorActor.GetCurrentSize();
+
+    if(mReadPosition.x >= position.x &&
+       mReadPosition.x <= position.x + size.width &&
+       mReadPosition.y >= position.y &&
+       mReadPosition.y <= position.y + size.height)
+    {
+      indicatorFocused = true;
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Indicator area!!!!\n", __FUNCTION__, __LINE__);
+    }
+  }
+
+  if( mIndicator )
+  {
+    if( !mIndicatorFocused && indicatorFocused )
+    {
+      // If Indicator is focused, the focus should be cleared in Dali focus chain.
+      if( mActionHandler )
+      {
+        mActionHandler->ClearAccessibilityFocus();
+      }
+    }
+
+    mIndicatorFocused = indicatorFocused;
+
+    // Send accessibility READ action information to Indicator
+    if( mIndicatorFocused )
+    {
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Send READ message to indicator!!!!\n", __FUNCTION__, __LINE__);
+    }
+  }
+
+  if( mActionHandler && !mIndicatorFocused)
+  {
+    // If Indicator is not focused, the accessibility actions should be handled by the registered
+    // accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead( allowReadAgain );
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageLeft();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageRight();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToFirst();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToLast();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromTop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromNext();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionZoom();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadIndicatorInformation();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPauseResume();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionStartStop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/accessibility-adaptor-impl.h b/adaptors/ubuntu/accessibility-adaptor-impl.h
new file mode 100644 (file)
index 0000000..82f2e70
--- /dev/null
@@ -0,0 +1,301 @@
+#ifndef __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
+#define __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/integration-api/events/touch-event-combiner.h>
+
+// INTERNAL INCLUDES
+#include <accessibility-adaptor.h>
+#include <accessibility-action-handler.h>
+#include <accessibility-gesture-handler.h>
+#include <indicator-impl.h>
+#include <accessibility-gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This class detects to accessibility action
+ */
+class AccessibilityAdaptor : public Dali::BaseObject
+{
+public:
+
+  // Creation
+
+  /**
+   * Constructor.
+   */
+  AccessibilityAdaptor();
+
+  /**
+   * Get an instance of the AccessibilityAdaptor.
+   * @return The instance of the AccessibilityAdaptor.
+   */
+  static Dali::AccessibilityAdaptor Get();
+
+  // Public API
+
+  /**
+   * Turn on accessibility action
+   * This method should be called by vconf callback
+   */
+  void EnableAccessibility();
+
+  /**
+   * Turn off accessibility action
+   * This method should be called by vconf callback
+   */
+  void DisableAccessibility();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::IsEnabled()
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::GetReadPosition() const
+   */
+  Vector2 GetReadPosition() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetActionHandler()
+   */
+  void SetActionHandler(AccessibilityActionHandler& handler);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetGestureHandler()
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  /**
+   * Set the Indicator
+   */
+  void SetIndicator(Indicator* indicator);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent()
+   */
+  bool HandleActionNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent()
+   */
+  bool HandleActionPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent()
+   */
+  bool HandleActionActivateEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent()
+   */
+  bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent()
+   */
+  bool HandleActionReadNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent()
+   */
+  bool HandleActionReadPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent()
+   */
+  bool HandleActionUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent()
+   */
+  bool HandleActionDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionClearFocusEvent()
+   */
+  bool HandleActionClearFocusEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollEvent()
+   */
+  bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionTouchEvent()
+   */
+  bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionBackEvent()
+   */
+  bool HandleActionBackEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionEnableEvent()
+   */
+  void HandleActionEnableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDisableEvent()
+   */
+  void HandleActionDisableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollUpEvent()
+   */
+  bool HandleActionScrollUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollDownEvent()
+   */
+  bool HandleActionScrollDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageLeftEvent()
+   */
+  bool HandleActionPageLeftEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageRightEvent()
+   */
+  bool HandleActionPageRightEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageUpEvent()
+   */
+  bool HandleActionPageUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageDownEvent()
+   */
+  bool HandleActionPageDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+   */
+  bool HandleActionMoveToFirstEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToLastEvent()
+   */
+  bool HandleActionMoveToLastEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromTopEvent()
+   */
+  bool HandleActionReadFromTopEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromNextEvent()
+   */
+  bool HandleActionReadFromNextEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionZoomEvent()
+   */
+  bool HandleActionZoomEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+   */
+  bool HandleActionReadIndicatorInformationEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+   */
+  bool HandleActionReadPauseResumeEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionStartStopEvent()
+   */
+  bool HandleActionStartStopEvent();
+
+private:
+
+  // Destruction
+
+  /**
+   * Destructor.
+   */
+  virtual ~AccessibilityAdaptor();
+
+  // Undefined
+  AccessibilityAdaptor( const AccessibilityAdaptor& );
+  AccessibilityAdaptor& operator=( AccessibilityAdaptor& );
+
+private:
+
+  Dali::Integration::TouchEventCombiner mCombiner; ///< Combines multi-touch events.
+
+  bool mIsEnabled; ///< enable/disable the accessibility action
+  Vector2 mReadPosition; ///< ActionRead position
+
+  AccessibilityActionHandler* mActionHandler; ///< The pointer of accessibility action handler
+
+  AccessibilityGestureDetectorPtr mAccessibilityGestureDetector; ///< The accessibility gesture detector
+
+  Indicator* mIndicator; ///< The indicator
+  bool mIndicatorFocused; ///< Whether the Indicator is focused
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+  inline static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    const BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H__
diff --git a/adaptors/ubuntu/adaptor-impl-ubuntu.cpp b/adaptors/ubuntu/adaptor-impl-ubuntu.cpp
new file mode 100644 (file)
index 0000000..118816e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void Adaptor::GetDataStoragePath( std::string& path)
+{
+  path = DALI_SHADERBIN_DIR;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/file.list b/adaptors/ubuntu/file.list
new file mode 100644 (file)
index 0000000..feee7e9
--- /dev/null
@@ -0,0 +1,10 @@
+# ubuntu
+
+adaptor_ubuntu_internal_src_files = \
+  $(adaptor_ubuntu_dir)/accessibility-adaptor-impl-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/adaptor-impl-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/framework-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/vsync-monitor-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/tilt-sensor-impl-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/tts-player-impl-ubuntu.cpp \
+  $(adaptor_ubuntu_dir)/key-mapping-ubuntu.cpp
diff --git a/adaptors/ubuntu/framework-ubuntu.cpp b/adaptors/ubuntu/framework-ubuntu.cpp
new file mode 100644 (file)
index 0000000..1edd301
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "framework.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Elementary.h>
+#include <X11/Xlib.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <callback-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+/// Application Status Enum
+enum
+{
+  APP_CREATE,
+  APP_TERMINATE,
+  APP_PAUSE,
+  APP_RESUME,
+  APP_RESET,
+  APP_LANGUAGE_CHANGE,
+};
+
+} // Unnamed namespace
+
+/**
+ * Impl to hide EFL data members
+ */
+struct Framework::Impl
+{
+  // Constructor
+
+  Impl(void* data)
+  : mAbortCallBack( NULL ),
+    mCallbackManager( CallbackManager::New() )
+  {
+  }
+
+  ~Impl()
+  {
+    delete mAbortCallBack;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+  }
+
+  // Data
+
+  CallbackBase* mAbortCallBack;
+  CallbackManager *mCallbackManager;
+  // Static methods
+
+  /**
+   * Called by AppCore on application creation.
+   */
+  static bool AppCreate(void *data)
+  {
+    return static_cast<Framework*>(data)->AppStatusHandler(APP_CREATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application should terminate.
+   */
+  static void AppTerminate(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_TERMINATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is paused.
+   */
+  static void AppPause(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_PAUSE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is resumed.
+   */
+  static void AppResume(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_RESUME, NULL);
+  }
+
+  /**
+   * Called by AppCore when the language changes on the device.
+   */
+  static void AppLanguageChange(void* data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_LANGUAGE_CHANGE, NULL);
+  }
+
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv )
+: mObserver(observer),
+  mInitialised(false),
+  mRunning(false),
+  mArgc(argc),
+  mArgv(argv),
+  mBundleName(""),
+  mBundleId(""),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl(NULL)
+{
+  InitThreads();
+  mImpl = new Impl(this);
+}
+
+Framework::~Framework()
+{
+  if (mRunning)
+  {
+    Quit();
+  }
+
+  delete mImpl;
+}
+
+void Framework::Run()
+{
+  mRunning = true;
+
+  elm_init(*mArgc, *mArgv);
+
+  Impl::AppCreate(this);
+
+  elm_run();
+
+  mRunning = false;
+}
+
+void Framework::Quit()
+{
+  Impl::AppTerminate(this);
+
+  elm_exit();
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if (mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void *bundleData)
+{
+  switch (type)
+  {
+    case APP_CREATE:
+    {
+      mInitialised = true;
+
+      // Connect to abnormal exit signals
+      mAbortHandler.AbortOnSignal( SIGINT );
+      mAbortHandler.AbortOnSignal( SIGQUIT );
+      mAbortHandler.AbortOnSignal( SIGKILL );
+
+      mObserver.OnInit();
+      break;
+    }
+
+    case APP_RESET:
+      mObserver.OnReset();
+      break;
+
+    case APP_RESUME:
+      mObserver.OnResume();
+      break;
+
+    case APP_TERMINATE:
+     mObserver.OnTerminate();
+      break;
+
+    case APP_PAUSE:
+      mObserver.OnPause();
+      break;
+
+    case APP_LANGUAGE_CHANGE:
+      mObserver.OnLanguageChanged();
+      break;
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+void Framework::InitThreads()
+{
+  XInitThreads();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/key-mapping-ubuntu.cpp b/adaptors/ubuntu/key-mapping-ubuntu.cpp
new file mode 100644 (file)
index 0000000..53c18de
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "key-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,          false },
+  { "Menu",                  DALI_KEY_MENU,            false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,      false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,     false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable ))/ (sizeof( KeyLookup ));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/tilt-sensor-impl-ubuntu.cpp b/adaptors/ubuntu/tilt-sensor-impl-ubuntu.cpp
new file mode 100644 (file)
index 0000000..482b173
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tilt-sensor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace // unnamed namespace
+{
+
+const char* const SIGNAL_TILTED = "tilted";
+
+const int NUMBER_OF_SAMPLES = 10;
+
+const float MAX_ACCELEROMETER_XY_VALUE = 9.8f;
+
+// Type Registration
+Dali::BaseHandle GetInstance()
+{
+  return Dali::Internal::Adaptor::TiltSensor::Get();
+}
+
+Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), GetInstance );
+
+Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::TiltSensor TiltSensor::New()
+{
+  Dali::TiltSensor sensor = Dali::TiltSensor(new TiltSensor());
+
+  return sensor;
+}
+
+Dali::TiltSensor TiltSensor::Get()
+{
+  Dali::TiltSensor sensor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the keyboard focus manager is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TiltSensor ) );
+    if(handle)
+    {
+      // If so, downcast the handle of singleton to keyboard focus manager
+      sensor = Dali::TiltSensor( dynamic_cast< TiltSensor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      // Create a singleton instance
+      sensor = TiltSensor::New();
+      service.Register( typeid( sensor ), sensor );
+      handle = sensor;
+    }
+  }
+
+  return sensor;
+}
+
+TiltSensor::~TiltSensor()
+{
+  Disable();
+}
+
+bool TiltSensor::Enable()
+{
+  // Make sure sensor API is responding
+  bool success = Update();
+
+  if ( success )
+  {
+    if ( !mTimer )
+    {
+      mTimer = Dali::Timer::New( 1000.0f / mFrequencyHertz );
+      mTimer.TickSignal().Connect( mTimerSlot, &TiltSensor::Update );
+    }
+
+    if ( mTimer &&
+         !mTimer.IsRunning() )
+    {
+      mTimer.Start();
+    }
+  }
+
+  return success;
+}
+
+void TiltSensor::Disable()
+{
+  if ( mTimer )
+  {
+    mTimer.Stop();
+    mTimer.Reset();
+  }
+}
+
+bool TiltSensor::IsEnabled() const
+{
+  return ( mTimer && mTimer.IsRunning() );
+}
+
+float TiltSensor::GetRoll() const
+{
+  return mRoll;
+}
+
+float TiltSensor::GetPitch() const
+{
+  return mPitch;
+}
+
+Quaternion TiltSensor::GetRotation() const
+{
+  return mRotation;
+}
+
+TiltSensor::TiltedSignalType& TiltSensor::TiltedSignal()
+{
+  return mTiltedSignal;
+}
+
+void TiltSensor::SetUpdateFrequency( float frequencyHertz )
+{
+  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );
+
+  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
+  {
+    mFrequencyHertz = frequencyHertz;
+
+    if ( mTimer )
+    {
+      mTimer.SetInterval( 1000.0f / mFrequencyHertz );
+    }
+  }
+}
+
+float TiltSensor::GetUpdateFrequency() const
+{
+  return mFrequencyHertz;
+}
+
+void TiltSensor::SetRotationThreshold(Radian rotationThreshold)
+{
+  mRotationThreshold = rotationThreshold;
+}
+
+Radian TiltSensor::GetRotationThreshold() const
+{
+  return mRotationThreshold;
+}
+
+bool TiltSensor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );
+
+  if( sensor && ( SIGNAL_TILTED == signalName ) )
+  {
+    sensor->TiltedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+TiltSensor::TiltSensor()
+: mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
+  mTimerSlot( this ),
+  mSensorFrameworkHandle( -1 ),
+  mRoll( 0.0f ),
+  mPitch( 0.0f ),
+  mRotation( Dali::ANGLE_0, Vector3::YAXIS ),
+  mRotationThreshold( 0.0f )
+{
+  mRollValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+  mPitchValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+}
+
+bool TiltSensor::Update()
+{
+  float newRoll = 0.0f;
+  float newPitch = 0.0f;
+  Quaternion newRotation;
+
+  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));
+  // If the change in value is more than the threshold then emit tilted signal.
+  if( angle > mRotationThreshold )
+  {
+    mRoll = newRoll;
+    mPitch = newPitch;
+    mRotation = newRotation;
+
+    if ( !mTiltedSignal.Empty() )
+    {
+      Dali::TiltSensor handle( this );
+      mTiltedSignal.Emit( handle );
+    }
+  }
+
+  return true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/ubuntu/tilt-sensor-impl.h b/adaptors/ubuntu/tilt-sensor-impl.h
new file mode 100644 (file)
index 0000000..4f864ad
--- /dev/null
@@ -0,0 +1,194 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
+#define __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <deque>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <tilt-sensor.h>
+#include <timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ */
+class TiltSensor : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::TiltSensor::TiltedSignalType TiltedSignalType;
+
+  /**
+   * Create a TiltSensor.
+   * This should only be called once by the Adaptor class.
+   * @return A newly allocated tilt-sensor.
+   */
+  static Dali::TiltSensor New();
+
+  /**
+   * @copydoc Dali::TiltSensor::Get()
+   */
+  static Dali::TiltSensor Get();
+
+  /**
+   * @copydoc Dali::TiltSensor::Enable()
+   */
+  bool Enable();
+
+  /**
+   * @copydoc Dali::TiltSensor::Disable()
+   */
+  void Disable();
+
+  /**
+   * @copydoc Dali::TiltSensor::IsEnabled()
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRoll()
+   */
+  float GetRoll() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetPitch()
+   */
+  float GetPitch() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotation()
+   */
+  Quaternion GetRotation() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::TiltedSignal()
+   */
+  TiltedSignalType& TiltedSignal();
+
+  /**
+   * @copydoc Dali::TiltSensor::SetUpdateFrequency()
+   */
+  void SetUpdateFrequency( float frequencyHertz );
+
+  /**
+   * @copydoc Dali::TiltSensor::GetUpdateFrequency()
+   */
+  float GetUpdateFrequency() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetRotationThreshold()
+   */
+  void SetRotationThreshold(Radian rotationThreshold);
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotationThreshold()
+   */
+  Radian GetRotationThreshold() const;
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * Private constructor; see also TiltSensor::New()
+   */
+  TiltSensor();
+
+  /**
+   * Destructor
+   */
+  virtual ~TiltSensor();
+
+  /**
+   * Timer callback to update the tilt values
+   */
+  bool Update();
+
+  // Undefined
+  TiltSensor(const TiltSensor&);
+
+  // Undefined
+  TiltSensor& operator=(TiltSensor&);
+
+private:
+
+  float mFrequencyHertz;
+  Dali::Timer mTimer;
+  SlotDelegate< TiltSensor > mTimerSlot;
+
+  int mSensorFrameworkHandle;
+
+  float mRoll;
+  float mPitch;
+  Quaternion mRotation;
+
+  Radian mRotationThreshold;
+
+  std::deque<float> mRollValues;
+  std::deque<float> mPitchValues;
+
+  TiltedSignalType mTiltedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::TiltSensor& GetImplementation(Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TiltSensor&>(handle);
+}
+
+inline const Internal::Adaptor::TiltSensor& GetImplementation(const Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  const BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TiltSensor&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ADAPTOR_TILT_SENSOR_H__
diff --git a/adaptors/ubuntu/tts-player-impl-ubuntu.cpp b/adaptors/ubuntu/tts-player-impl-ubuntu.cpp
new file mode 100644 (file)
index 0000000..54c1cdf
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "tts-player-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return Dali::TtsPlayer::Get() ;
+}
+
+Dali::TypeRegistration mType( typeid(Dali::TtsPlayer), typeid(Dali::BaseHandle), Create ) ;
+} // unnamed namespace
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* TtsPlayer::gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TTS_PLAYER");
+#endif
+
+Dali::TtsPlayer TtsPlayer::New(Dali::TtsPlayer::Mode mode)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer(new TtsPlayer(mode));
+
+  return player;
+}
+
+TtsPlayer::TtsPlayer(Dali::TtsPlayer::Mode mode)
+{
+  DALI_LOG_ERROR("TTS is not implemented in UBUNTU profile.");
+}
+
+TtsPlayer::~TtsPlayer()
+{
+}
+
+void TtsPlayer::Play(const std::string& text)
+{
+}
+
+void TtsPlayer::Stop()
+{
+}
+
+void TtsPlayer::Pause()
+{
+}
+
+void TtsPlayer::Resume()
+{
+}
+
+Dali::TtsPlayer::State TtsPlayer::GetState()
+{
+  return Dali::TtsPlayer::UNAVAILABLE;
+}
+
+Dali::TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  return mStateChangedSignal;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/adaptors/ubuntu/tts-player-impl.h b/adaptors/ubuntu/tts-player-impl.h
new file mode 100644 (file)
index 0000000..22dcd41
--- /dev/null
@@ -0,0 +1,139 @@
+#ifndef __DALI_INTERNAL_TTS_PLAYER_H__
+#define __DALI_INTERNAL_TTS_PLAYER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+#include <string>
+
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/base-object.h>
+#include <tts-player.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Text-to-speech player
+ */
+class TtsPlayer : public Dali::BaseObject
+{
+
+public:
+
+  /**
+   * Create a TtsPlayer with the given mode.
+   * This should only be called once by the Adaptor class for each given mode.
+   * @param mode the mode of tts-player
+   * @return A newly created TtsPlayer.
+   */
+  static Dali::TtsPlayer New(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc TtsPlayer::Play()
+   */
+  void Play(const std::string& text);
+
+  /**
+   * @copydoc TtsPlayer::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc TtsPlayer::Pause()
+   */
+  void Pause();
+
+  /**
+   * @copydoc TtsPlayer::Resume()
+   */
+  void Resume();
+
+  /**
+   * @copydoc TtsPlayer::GetState()
+   */
+  Dali::TtsPlayer::State GetState();
+
+  /**
+   * @copydoc TtsPlayer::StateChangedSignal()
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal();
+
+private:
+
+  /**
+   * Private Constructor; see also TtsPlayer::New()
+   * @param mode the mode of tts-player
+   */
+  TtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * Destructor
+   */
+  virtual ~TtsPlayer();
+
+private:
+
+  Dali::TtsPlayer::StateChangedSignalType mStateChangedSignal; ///< Signal emitted when the TTS state changes (non-functional, for interface compatibility).
+  std::string mUnplayedString; ///< The text that can not be played because tts engine is not yet initialized
+  int mUtteranceId;  ///< The utterance ID
+
+  Dali::TtsPlayer::Mode mTtsMode; ///< The current mode of tts engine
+
+#if defined(DEBUG_ENABLED)
+public:
+  static Debug::Filter* gLogFilter;
+#endif
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::TtsPlayer& GetImplementation(Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::TtsPlayer& GetImplementation(const Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TTS_PLAYER_H__
diff --git a/adaptors/ubuntu/vsync-monitor-ubuntu.cpp b/adaptors/ubuntu/vsync-monitor-ubuntu.cpp
new file mode 100644 (file)
index 0000000..af8d4c9
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "vsync-monitor.h"
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
+const unsigned int TRUE = 1u;
+const unsigned int FALSE = 0u;
+
+const int FD_NONE( -1 );
+
+} // unnamed namespace
+
+VSyncMonitor::VSyncMonitor()
+: mFileDescriptor( FD_NONE ),
+  mUseHardwareVSync( FALSE ),
+  mHardwareVSyncAvailable( FALSE )
+{
+}
+
+VSyncMonitor::~VSyncMonitor()
+{
+  Terminate();
+}
+
+void VSyncMonitor::SetUseHardwareVSync( bool useHardware )
+{
+  mUseHardwareVSync = useHardware;
+}
+
+void VSyncMonitor::SetHardwareVSyncAvailable( bool hardwareVSyncAvailable )
+{
+  mHardwareVSyncAvailable = hardwareVSyncAvailable;
+}
+
+void VSyncMonitor::Initialize()
+{
+  DALI_ASSERT_DEBUG( mFileDescriptor == FD_NONE && "VSyncMonitor::Initialize() called twice" );
+
+  // setup vblank request - block and wait for next vblank
+  mVBlankInfo.request.type = DRM_VBLANK_NEXTONMISS;
+  mVBlankInfo.request.sequence = 0;
+  mVBlankInfo.request.signal = 0;
+
+  // setup vblank reply - block and wait for next vblank
+  mVBlankInfo.reply.type = DRM_VBLANK_NEXTONMISS;
+  mVBlankInfo.reply.sequence = 0;
+  mVBlankInfo.reply.tval_sec = 0;
+  mVBlankInfo.reply.tval_usec = 0;
+}
+
+void VSyncMonitor::Terminate()
+{
+}
+
+bool VSyncMonitor::UseHardware()
+{
+  return mUseHardwareVSync && mHardwareVSyncAvailable && (FD_NONE != mFileDescriptor );
+}
+
+
+bool VSyncMonitor::DoSync( unsigned int& frameNumber, unsigned int& seconds, unsigned int& microseconds )
+{
+  DALI_ASSERT_DEBUG( mFileDescriptor != FD_NONE && "ECoreX::VSyncMonitor is not initialized" );
+
+  if( 0 == drmWaitVBlank( mFileDescriptor, &mVBlankInfo ) )
+  {
+    frameNumber = mVBlankInfo.reply.sequence;
+    seconds = mVBlankInfo.reply.tval_sec;
+    microseconds = mVBlankInfo.reply.tval_usec;
+
+    return true;
+  }
+
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/accessibility-adaptor-impl-wl.cpp b/adaptors/wayland/accessibility-adaptor-impl-wl.cpp
new file mode 100644 (file)
index 0000000..d5a166f
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "accessibility-adaptor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <Elementary.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/gesture-requests.h>
+
+// INTERNAL INCLUDES
+#include "system-settings.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  Dali::AccessibilityAdaptor handle( this );
+
+  bool indicatorFocused = false;
+
+  // Check whether the Indicator is focused
+  if( mIndicator && mIndicator->IsConnected() )
+  {
+    // Check the position and size of Indicator actor
+    Dali::Actor indicatorActor = mIndicator->GetActor();
+    Vector3 position = Vector3(0.0f, 0.0f, 0.0f);
+    Vector3 size = indicatorActor.GetCurrentSize();
+
+    if(mReadPosition.x >= position.x &&
+       mReadPosition.x <= position.x + size.width &&
+       mReadPosition.y >= position.y &&
+       mReadPosition.y <= position.y + size.height)
+    {
+      indicatorFocused = true;
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Indicator area!!!!\n", __FUNCTION__, __LINE__);
+    }
+  }
+
+  if( mIndicator )
+  {
+    if( !mIndicatorFocused && indicatorFocused )
+    {
+      // If Indicator is focused, the focus should be cleared in Dali focus chain.
+      if( mActionHandler )
+      {
+        mActionHandler->ClearAccessibilityFocus();
+      }
+    }
+    else if( mIndicatorFocused && !indicatorFocused )
+    {
+    }
+
+    mIndicatorFocused = indicatorFocused;
+
+    // Send accessibility READ action information to Indicator
+    if( mIndicatorFocused )
+    {
+    }
+  }
+
+  if( mActionHandler && !mIndicatorFocused)
+  {
+    // If Indicator is not focused, the accessibility actions should be handled by the registered
+    // accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead(allowReadAgain);
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  Dali::AccessibilityAdaptor handle( this );
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  Dali::AccessibilityAdaptor handle( this );
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageLeft();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageRight();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToFirst();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToLast();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromTop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromNext();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionZoom();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadIndicatorInformation();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPauseResume();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionStartStop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/clipboard-impl-wl.cpp b/adaptors/wayland/clipboard-impl-wl.cpp
new file mode 100644 (file)
index 0000000..6c1ff67
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "clipboard-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+namespace //unnamed namespace
+{
+const char* const CBHM_WINDOW = "CBHM_XWIN";
+const char* const CBHM_MSG = "CBHM_MSG";
+const char* const CBHM_ITEM = "CBHM_ITEM";
+const char* const CBHM_cCOUNT = "CBHM_cCOUNT";
+const char* const CBHM_ERROR = "CBHM_ERROR";
+const char* const SET_ITEM = "SET_ITEM";
+const char* const SHOW = "show0";
+const char* const HIDE = "cbhm_hide";
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+BaseHandle Create()
+{
+  BaseHandle handle( Clipboard::Get() );
+
+  return handle;
+}
+TypeRegistration CLIPBOARD_TYPE( typeid(Dali::Clipboard), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Clipboard::~Clipboard()
+{
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  Dali::Clipboard clipboard;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Clipboard ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      clipboard = Dali::Clipboard( dynamic_cast< Clipboard* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return clipboard;
+}
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  return true;
+}
+
+/*
+ * Get string at given index of clipboard
+ */
+std::string Clipboard::GetItem( unsigned int index )  // change string to a Dali::Text object.
+{
+  if ( index >= NumberOfItems() )
+  {
+    return "";
+  }
+
+  std::string emptyString( "" );
+  char sendBuf[20];
+
+  snprintf( sendBuf, 20,  "%s%d", CBHM_ITEM, index );
+  return emptyString;
+}
+
+/*
+ * Get number of items in clipboard
+ */
+unsigned int Clipboard::NumberOfItems()
+{
+  int count = -1;
+
+  return count;
+}
+
+/**
+ * Show clipboard window
+ * Function to send message to show the Clipboard (cbhm) as no direct API available
+ * Reference elementary/src/modules/ctxpopup_copypasteUI/cbhm_helper.c
+ */
+void Clipboard::ShowClipboard()
+{
+}
+
+void Clipboard::HideClipboard()
+{
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/clipboard-impl.h b/adaptors/wayland/clipboard-impl.h
new file mode 100644 (file)
index 0000000..1275479
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __DALI_INTERNAL_CLIPBOARD_H__
+#define __DALI_INTERNAL_CLIPBOARD_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+
+// INTERNAL INCLUDES
+#include <clipboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Clip Board
+ */
+
+class Clipboard :  public Dali::BaseObject
+{
+public:
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::Clipboard Get();
+
+  virtual ~Clipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::SetItem()
+   */
+  bool SetItem(const std::string &itemData);
+
+  /**
+   * @copydoc Dali::Clipboard::GetItem()
+   */
+  std::string GetItem( unsigned int index );
+
+  /**
+   * @copydoc Dali::Clipboard::NumberOfClipboardItems()
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @copydoc Dali::Clipboard::ShowClipboard()
+   */
+  void ShowClipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::HideClipboard()
+   */
+  void HideClipboard();
+
+  
+private:
+  Clipboard( const Clipboard& );
+  Clipboard& operator=( Clipboard& );
+
+}; // class clipboard
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+  inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard)
+  {
+    DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+    BaseObject& handle = clipboard.GetBaseObject();
+    return static_cast<Internal::Adaptor::Clipboard&>(handle);
+  }
+
+  inline static const  Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard)
+  {
+    DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+    const BaseObject& handle = clipboard.GetBaseObject();
+    return static_cast<const Internal::Adaptor::Clipboard&>(handle);
+  }
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CLIPBOARD_H__
diff --git a/adaptors/wayland/display-connection-impl-wl.cpp b/adaptors/wayland/display-connection-impl-wl.cpp
new file mode 100644 (file)
index 0000000..e708842
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "display-connection-impl.h"
+
+// EXTERNAL_HEADERS
+#include <Ecore_Wayland.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <pixmap-render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+DisplayConnection* DisplayConnection::New()
+{
+  DisplayConnection* pDisplayConnection(new DisplayConnection());
+
+  return pDisplayConnection;
+}
+
+DisplayConnection::DisplayConnection()
+: mDisplay(NULL)
+{
+  mDisplay = ecore_wl_display_get();
+}
+
+DisplayConnection::~DisplayConnection()
+{
+  //FIXME
+}
+
+Any DisplayConnection::GetDisplay()
+{
+  return Any(mDisplay);
+}
+
+void DisplayConnection::ConsumeEvents()
+{
+}
+
+bool DisplayConnection::InitializeEgl(EglInterface& egl)
+{
+  EglImplementation& eglImpl = static_cast<EglImplementation&>(egl);
+
+  if (!eglImpl.InitializeGles(reinterpret_cast<EGLNativeDisplayType>(mDisplay)))
+  {
+    DALI_LOG_ERROR("Failed to initialize GLES.");
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayConnection::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
+{
+  // calculate DPI
+  float xres, yres;
+
+  // 1 inch = 25.4 millimeters
+  xres = ecore_wl_dpi_get();
+  yres = ecore_wl_dpi_get();
+
+  dpiHorizontal = int(xres + 0.5f);  // rounding
+  dpiVertical   = int(yres + 0.5f);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/display-connection-impl.h b/adaptors/wayland/display-connection-impl.h
new file mode 100644 (file)
index 0000000..49ba200
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
+#define __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <wayland-egl.h>
+#include <Ecore_Wayland.h>
+#include <ecore-wl-types.h>
+
+// INTERNAL INCLUDES
+#include <base/display-connection.h>
+#include <dali/public-api/object/base-object.h>
+#include <gl/egl-implementation.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+class DisplayConnection;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnection : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnection();
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  Any GetDisplay();
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDpi
+   */
+  static void GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical);
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  void ConsumeEvents();
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeEgl
+   */
+  bool InitializeEgl(EglInterface& egl);
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~DisplayConnection();
+
+protected:
+
+  // Undefined
+  DisplayConnection(const DisplayConnection&);
+
+  // Undefined
+  DisplayConnection& operator=(const DisplayConnection& rhs);
+
+private:
+  WlDisplay*   mDisplay;        ///< Wayland-display for rendering
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
diff --git a/adaptors/wayland/ecore-wl-render-surface-factory.cpp b/adaptors/wayland/ecore-wl-render-surface-factory.cpp
new file mode 100644 (file)
index 0000000..60de84e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <ecore-wl-render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+DALI_EXPORT_API RenderSurface* CreatePixmapSurface(
+  PositionSize       positionSize,
+  Any                surface,
+  Any                display,
+  const std::string& name,
+  bool               isTransparent )
+{
+  return NULL;
+}
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+
diff --git a/adaptors/wayland/ecore-wl-render-surface-factory.h b/adaptors/wayland/ecore-wl-render-surface-factory.h
new file mode 100644 (file)
index 0000000..51ff9f2
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_ECORE_WL_RENDER_SURFACE_FACTORY_H__
+#define __DALI_INTERNAL_ADAPTOR_ECORE_WL_RENDER_SURFACE_FACTORY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <native-buffer-pool.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+class RenderSurface;
+
+/**
+ * Surface factory function for pixmap
+ * A pixmap surface is created.
+ *
+ * @param [in] type the type of surface to create
+ * @param [in] positionSize the position and size of the surface to create
+ * @param [in] display Wayland Pixmap to use, or null for default.
+ * @param [in] display Wayland Display to use, or null for default.
+ * @param [in] name Name of surface passed in
+ * @param [in] isTransparent Whether the surface has an alpha channel
+ */
+RenderSurface* CreatePixmapSurface(
+  PositionSize       positionSize,
+  Any         surface,
+  Any         display,
+  const std::string& name,
+  bool               isTransparent );
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif //  __DALI_INTERNAL_ADAPTOR_ECORE_X_RENDER_SURFACE_FACTORY_H__
diff --git a/adaptors/wayland/ecore-wl-render-surface.cpp b/adaptors/wayland/ecore-wl-render-surface.cpp
new file mode 100644 (file)
index 0000000..d6f0516
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "ecore-wl-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <ecore-wl-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_ECORE_X_RENDER_SURFACE");
+#endif
+
+namespace ECore
+{
+
+EcoreWlRenderSurface::EcoreWlRenderSurface(Dali::PositionSize positionSize,
+                                           Any surface,
+                                           const std::string& name,
+                                           bool isTransparent)
+: mPosition(positionSize),
+  mTitle(name),
+  mRenderNotification(NULL),
+  mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
+  mOwnSurface(false)
+{
+}
+
+void EcoreWlRenderSurface::Init( Any surface )
+{
+  // see if there is a surface in Any surface
+  unsigned int surfaceId  = GetSurfaceId( surface );
+
+  // if the surface is empty, create a new one.
+  if ( surfaceId == 0 )
+  {
+    // we own the surface about to created
+    ecore_wl_init(NULL);
+    mOwnSurface = true;
+    CreateWlRenderable();
+  }
+  else
+  {
+    // XLib should already be initialized so no point in calling XInitThreads
+    UseExistingRenderable( surfaceId );
+  }
+
+#ifdef DEBUG_ENABLED
+  // prints out 'INFO: DALI: new EcoreWlRenderSurface, created display xx, used existing surface xx
+  // we can not use LOG_INFO because the surface can be created before Dali Core is created.
+  printf( "INFO: DALI: new EcoreWlRenderSurface, %s %s surface %X \n",
+          mOwnSurface?"created":"used existing",
+          Dali::RenderSurface::PIXMAP==mType?" pixmap" :"window",
+          GetDrawable() );
+#endif
+}
+
+EcoreWlRenderSurface::~EcoreWlRenderSurface()
+{
+}
+
+void EcoreWlRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
+{
+  mRenderNotification = renderNotification;
+}
+
+Ecore_Wl_Window* EcoreWlRenderSurface::GetWlWindow()
+{
+  return 0;
+}
+
+Ecore_Wl_Window* EcoreWlRenderSurface::GetDrawable()
+{
+  return 0;
+}
+
+PositionSize EcoreWlRenderSurface::GetPositionSize() const
+{
+  return mPosition;
+}
+
+void EcoreWlRenderSurface::MoveResize( Dali::PositionSize positionSize )
+{
+  // nothing to do in base class
+}
+
+void EcoreWlRenderSurface::SetViewMode( ViewMode viewMode )
+{
+}
+
+unsigned int EcoreWlRenderSurface::GetSurfaceId( Any surface ) const
+{
+  unsigned int surfaceId = 0;
+
+  if ( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (Ecore_Wl_Window *) ) )
+                        && "Surface type is invalid" );
+
+    surfaceId = AnyCast<unsigned int>( surface );
+  }
+  return surfaceId;
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/wayland/ecore_wl_private.h b/adaptors/wayland/ecore_wl_private.h
new file mode 100644 (file)
index 0000000..f74aade
--- /dev/null
@@ -0,0 +1,323 @@
+#ifndef _ECORE_WAYLAND_PRIVATE_H
+# define _ECORE_WAYLAND_PRIVATE_H
+
+# include <limits.h>
+# include <unistd.h>
+
+# include "Ecore.h"
+# include "Ecore_Input.h"
+# include "Ecore_Wayland.h"
+# ifdef USE_IVI_SHELL
+# include "ivi-application-client-protocol.h"
+# define IVI_SURFACE_ID 6000
+# endif
+
+# include "tizen-policy-client-protocol.h"
+# include "tizen-extension-client-protocol.h"
+
+# include "keyrouter-client-protocol.h"
+
+//# define LOGFNS 1
+
+# ifdef LOGFNS
+#  include <stdio.h>
+#  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;
+
+# 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 CRI
+#  undef CRI
+# endif
+# define CRI(...) EINA_LOG_DOM_CRIT(_ecore_wl_log_dom, __VA_ARGS__)
+
+# ifdef ECORE_WL_DEFAULT_CURSOR_SIZE
+#  undef ECORE_WL_DEFAULT_CURSOR_SIZE
+# endif
+# define ECORE_WL_DEFAULT_CURSOR_SIZE 32
+
+typedef struct _Ecore_Wl_Display Ecore_Wl_Display;
+
+struct _Ecore_Wl_Display
+{
+   struct
+     {
+        struct wl_display *display;
+        struct wl_registry *registry;
+        struct wl_compositor *compositor;
+        struct wl_subcompositor *subcompositor;
+        struct wl_shell *shell;
+        struct xdg_shell *xdg_shell;
+        struct wl_shell *desktop_shell;
+# ifdef USE_IVI_SHELL
+        struct ivi_application *ivi_application;
+# endif
+        struct wl_shm *shm;
+        struct wl_data_device_manager *data_device_manager;
+        struct tizen_policy *tz_policy;
+        struct tizen_surface_extension *tz_surf_ext;
+        struct wl_keyrouter *keyrouter;
+     } wl;
+
+   int fd;
+   unsigned int mask;
+   unsigned int serial;
+   int sync_ref_count;
+   Ecore_Fd_Handler *fd_hdl;
+   Ecore_Idle_Enterer *idle_enterer;
+
+   Eina_Inlist *inputs;
+   Eina_Inlist *outputs;
+   Eina_Inlist *globals; /** @since 1.7.6 */
+
+   Eina_Bool init_done;
+
+   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_Window
+{
+   Ecore_Wl_Display *display;
+   Ecore_Wl_Window *parent;
+
+   struct wl_surface *surface;
+   struct wl_shell_surface *shell_surface;
+# ifdef USE_IVI_SHELL
+   struct ivi_surface *ivi_surface;
+   int ivi_surface_id;
+# endif
+   struct tizen_visibility *tz_visibility;
+   struct tizen_resource *tz_resource;
+   unsigned int resource_id;
+
+   struct wl_region *opaque_region;
+   struct wl_region *input_region;
+
+   struct xdg_surface *xdg_surface;
+   struct xdg_popup *xdg_popup;
+   Eina_Bool visible : 1;
+   Eina_Bool focused : 1;
+   Eina_Bool resizing : 1;
+
+   Eina_Bool fullscreen : 1;
+   Eina_Bool maximized : 1;
+   Eina_Bool minimized : 1;
+
+   struct
+     {
+        struct wl_surface *surface;
+        int hot_x, hot_y;
+        Eina_Bool set : 1;
+     } pointer;
+
+   int id, surface_id;
+   int rotation;
+
+   const char *title;
+   const char *class_name;
+
+   Eina_Rectangle allocation;
+
+   struct
+     {
+        int w, h;
+     } saved;
+
+   struct
+     {
+        int x, y, w, h;
+     } opaque, input;
+
+   /* Eina_Bool redraw_scheduled : 1; */
+   /* Eina_Bool resize_scheduled : 1; */
+   Eina_Bool alpha : 1;
+   Eina_Bool transparent : 1;
+   Eina_Bool has_buffer : 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 anim_pending : 1;
+   struct wl_callback *anim_callback;
+
+   const char *cursor_name;
+
+   Ecore_Wl_Subsurf *subsurfs;
+
+   void *data;
+};
+
+struct _Ecore_Wl_Input
+{
+   EINA_INLIST;
+   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_cursor *cursor;
+   struct wl_surface *cursor_surface;
+   struct wl_callback *cursor_frame_cb;
+   Ecore_Timer *cursor_timer;
+   unsigned int cursor_current_index;
+   unsigned int cursor_size;
+   const char *cursor_theme_name;
+
+   struct wl_data_device *data_device;
+   struct wl_data_source *data_source;
+   struct wl_array data_types;
+
+   Ecore_Wl_Window *pointer_focus;
+   Ecore_Wl_Window *keyboard_focus;
+   Ecore_Wl_Window *touch_focus;
+
+   unsigned int button;
+   unsigned int timestamp;
+   unsigned int modifiers;
+   unsigned int pointer_enter_serial;
+   int sx, sy;
+
+   Ecore_Wl_Window *grab;
+   unsigned int grab_button;
+   unsigned int grab_timestamp;
+   unsigned int grab_count;
+
+   Ecore_Wl_Dnd_Source *drag_source;
+   Ecore_Wl_Dnd_Source *selection_source;
+
+   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_mod_mask_t win_mask;
+        xkb_mod_mask_t scroll_mask;
+        xkb_mod_mask_t num_mask;
+        xkb_mod_mask_t caps_mask;
+        xkb_mod_mask_t altgr_mask;
+        unsigned int mods_depressed;
+        unsigned int mods_latched;
+        unsigned int mods_locked;
+        unsigned int mods_group;
+     } xkb;
+
+   struct
+     {
+        Ecore_Timer *tmr;
+        unsigned int sym, key, time;
+     } repeat;
+};
+
+struct _Ecore_Wl_Output
+{
+   EINA_INLIST;
+   Ecore_Wl_Display *display;
+   struct wl_output *output;
+   Eina_Rectangle allocation;
+   int mw, mh;
+   int transform;
+
+   void (*destroy) (Ecore_Wl_Output *output, void *data);
+   void *data;
+};
+
+struct _Ecore_Wl_Dnd
+{
+   Ecore_Wl_Display *ewd;
+   Ecore_Wl_Input *input;
+};
+
+struct _Ecore_Wl_Dnd_Source
+{
+   Ecore_Wl_Input *input;
+
+   struct wl_data_offer *data_offer;
+   struct wl_array types;
+
+   int refcount;
+   int fd;
+   int x, y;
+};
+
+struct _Ecore_Wl_Dnd_Target
+{
+   Ecore_Wl_Dnd_Source *source;
+};
+
+extern Ecore_Wl_Display *_ecore_wl_disp;
+
+void _ecore_wl_window_init(void);
+void _ecore_wl_window_shutdown(void);
+Eina_Hash *_ecore_wl_window_hash_get(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_grab_release(Ecore_Wl_Input *input, Ecore_Wl_Window *win);
+
+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, unsigned int timestamp, 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);
+void _ecore_wl_dnd_motion(void *data, struct wl_data_device *data_device, unsigned int timestamp, int x, int y);
+void _ecore_wl_dnd_drop(void *data, struct wl_data_device *data_device);
+void _ecore_wl_dnd_selection(void *data, struct wl_data_device *data_device, struct wl_data_offer *offer);
+void _ecore_wl_dnd_del(Ecore_Wl_Dnd_Source *source);
+
+void _ecore_wl_events_init(void);
+void _ecore_wl_events_shutdown(void);
+
+void _ecore_wl_subsurfs_del_all(Ecore_Wl_Window *win);
+
+struct wl_compositor *_ecore_wl_compositor_get(void);
+struct wl_subcompositor *_ecore_wl_subcompositor_get(void);
+
+#endif
diff --git a/adaptors/wayland/egl-implementation-wl.cpp b/adaptors/wayland/egl-implementation-wl.cpp
new file mode 100644 (file)
index 0000000..b91a1b8
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <wayland-egl.h>
+#include <gl/egl-implementation.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <ecore-wl-render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#define TEST_EGL_ERROR(lastCommand) \
+{ \
+  EGLint err = eglGetError(); \
+  if (err != EGL_SUCCESS) \
+  { \
+    DALI_LOG_ERROR("EGL error after %s code=%d\n", lastCommand,err); \
+    DALI_ASSERT_ALWAYS(0 && "EGL error");                            \
+  } \
+}
+
+EglImplementation::EglImplementation()
+  : mEglNativeDisplay(0),
+    mEglNativeWindow(0),
+    mEglNativePixmap(0),
+    mEglDisplay(0),
+    mEglConfig(0),
+    mEglContext(0),
+    mEglSurface(0),
+    mGlesInitialized(false),
+    mIsOwnSurface(true),
+    mContextCurrent(false),
+    mIsWindow(true),
+    mColorDepth(COLOR_DEPTH_24)
+{
+}
+
+EglImplementation::~EglImplementation()
+{
+  TerminateGles();
+}
+
+bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
+{
+  if ( !mGlesInitialized )
+  {
+    mEglNativeDisplay = display;
+
+    //@todo see if we can just EGL_DEFAULT_DISPLAY instead
+    mEglDisplay = eglGetDisplay(mEglNativeDisplay);
+    EGLint error = eglGetError();
+
+    if( mEglDisplay == NULL && error != EGL_SUCCESS )
+    {
+      throw Dali::DaliException( "", "OpenGL ES is not supported" );
+    }
+
+    EGLint majorVersion = 0;
+    EGLint minorVersion = 0;
+    if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
+    {
+      return false;
+    }
+    eglBindAPI(EGL_OPENGL_ES_API);
+
+    mContextAttribs.Clear();
+
+#if DALI_GLES_VERSION >= 30
+
+    mContextAttribs.Reserve(5);
+    mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
+    mContextAttribs.PushBack( 3 );
+    mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
+    mContextAttribs.PushBack( 0 );
+
+#else // DALI_GLES_VERSION >= 30
+
+    mContextAttribs.Reserve(3);
+    mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
+    mContextAttribs.PushBack( 2 );
+
+#endif // DALI_GLES_VERSION >= 30
+
+    mContextAttribs.PushBack( EGL_NONE );
+
+    mGlesInitialized = true;
+    mIsOwnSurface = isOwnSurface;
+  }
+
+  return mGlesInitialized;
+}
+
+bool EglImplementation::CreateContext()
+{
+  // make sure a context isn't created twice
+  DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
+
+  mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
+  TEST_EGL_ERROR("eglCreateContext render thread");
+
+  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
+
+  return true;
+}
+
+void EglImplementation::DestroyContext()
+{
+  DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
+
+  eglDestroyContext( mEglDisplay, mEglContext );
+  mEglContext = 0;
+}
+
+void EglImplementation::DestroySurface()
+{
+  if(mIsOwnSurface && mEglSurface)
+  {
+    eglDestroySurface( mEglDisplay, mEglSurface );
+    mEglSurface = 0;
+  }
+}
+
+void EglImplementation::MakeContextCurrent()
+{
+  mContextCurrent = true;
+
+  if(mIsOwnSurface)
+  {
+    eglMakeCurrent( mEglDisplay, mEglSurface, mEglSurface, mEglContext );
+  }
+
+  EGLint error = eglGetError();
+
+  if ( error != EGL_SUCCESS )
+  {
+    switch (error)
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR("EGL_BAD_DISPLAY : Display is not an EGL display connection");
+        break;
+      }
+      case EGL_NOT_INITIALIZED:
+      {
+        DALI_LOG_ERROR("EGL_NOT_INITIALIZED : Display has not been initialized");
+        break;
+      }
+      case EGL_BAD_SURFACE:
+      {
+        DALI_LOG_ERROR("EGL_BAD_SURFACE : Draw or read is not an EGL surface");
+        break;
+      }
+      case EGL_BAD_CONTEXT:
+      {
+        DALI_LOG_ERROR("EGL_BAD_CONTEXT : Context is not an EGL rendering context");
+        break;
+      }
+      case EGL_BAD_MATCH:
+      {
+        DALI_LOG_ERROR("EGL_BAD_MATCH : Draw or read are not compatible with context, or if context is set to EGL_NO_CONTEXT and draw or read are not set to EGL_NO_SURFACE, or if draw or read are set to EGL_NO_SURFACE and context is not set to EGL_NO_CONTEXT");
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR("EGL_BAD_ACCESS : Context is current to some other thread");
+        break;
+      }
+      case EGL_BAD_NATIVE_PIXMAP:
+      {
+        DALI_LOG_ERROR("EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or read is no longer valid.");
+        break;
+      }
+      case EGL_BAD_NATIVE_WINDOW:
+      {
+        DALI_LOG_ERROR("EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or read is no longer valid.");
+        break;
+      }
+      case EGL_BAD_CURRENT_SURFACE:
+      {
+        DALI_LOG_ERROR("EGL_BAD_CURRENT_SURFACE : The previous context has unflushed commands and the previous surface is no longer valid.");
+        break;
+      }
+      case EGL_BAD_ALLOC:
+      {
+        DALI_LOG_ERROR("EGL_BAD_ALLOC : Allocation of ancillary buffers for draw or read were delayed until eglMakeCurrent is called, and there are not enough resources to allocate them");
+        break;
+      }
+      case EGL_CONTEXT_LOST:
+      {
+        DALI_LOG_ERROR("EGL_CONTEXT_LOST : If a power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering");
+        break;
+      }
+      default:
+      {
+        DALI_LOG_ERROR("Unknown error");
+        break;
+      }
+    }
+    DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
+  }
+
+  // We want to display this information all the time, so use the LogMessage directly
+  Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
+      "            Vendor:        %s\n"
+      "            Version:       %s\n"
+      "            Client APIs:   %s\n"
+      "            Extensions:    %s\n",
+      eglQueryString(mEglDisplay, EGL_VENDOR),
+      eglQueryString(mEglDisplay, EGL_VERSION),
+      eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
+      eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+}
+
+void EglImplementation::MakeContextNull()
+{
+  mContextCurrent = false;
+  // clear the current context
+  eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+}
+
+void EglImplementation::TerminateGles()
+{
+  if ( mGlesInitialized )
+  {
+    // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
+    // MakeContextNull should be called before eglDestroy surface
+    // to prevent crash in _mali_surface_destroy_callback
+    MakeContextNull();
+
+    if(mIsOwnSurface && mEglSurface)
+    {
+      eglDestroySurface(mEglDisplay, mEglSurface);
+    }
+    eglDestroyContext(mEglDisplay, mEglContext);
+
+    eglTerminate(mEglDisplay);
+
+    mEglDisplay = NULL;
+    mEglConfig  = NULL;
+    mEglContext = NULL;
+    mEglSurface = NULL;
+
+    mGlesInitialized = false;
+  }
+}
+
+bool EglImplementation::IsGlesInitialized() const
+{
+  return mGlesInitialized;
+}
+
+void EglImplementation::SwapBuffers()
+{
+  eglSwapBuffers( mEglDisplay, mEglSurface );
+}
+
+void EglImplementation::CopyBuffers()
+{
+  eglCopyBuffers( mEglDisplay, mEglSurface, mEglNativePixmap );
+}
+
+void EglImplementation::WaitGL()
+{
+  eglWaitGL();
+}
+
+void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
+{
+  if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
+  {
+    return;
+  }
+
+  mIsWindow = isWindowType;
+
+  EGLint numConfigs;
+  Vector<EGLint> configAttribs;
+  configAttribs.Reserve(31);
+
+  if(isWindowType)
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_WINDOW_BIT );
+  }
+  else
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_PIXMAP_BIT );
+  }
+
+  configAttribs.PushBack( EGL_RENDERABLE_TYPE );
+
+#if DALI_GLES_VERSION >= 30
+
+#ifdef _ARCH_ARM_
+  configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
+#else
+  // There is a bug in the desktop emulator
+  // Requesting for ES3 causes eglCreateContext even though it allows to ask
+  // for a configuration that supports GLES 3.0
+  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
+#endif // _ARCH_ARM_
+
+#else // DALI_GLES_VERSION >= 30
+
+  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
+
+#endif //DALI_GLES_VERSION >= 30
+
+#if DALI_GLES_VERSION >= 30
+// TODO: enable this flag when it becomes supported
+//  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
+//  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
+#endif //DALI_GLES_VERSION >= 30
+
+  configAttribs.PushBack( EGL_RED_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_GREEN_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_BLUE_SIZE );
+  configAttribs.PushBack( 8 );
+
+  configAttribs.PushBack( EGL_ALPHA_SIZE );
+#ifdef _ARCH_ARM_
+  configAttribs.PushBack( (depth == COLOR_DEPTH_32) ? 8 : 0 );
+#else
+  // There is a bug in the desktop emulator
+  // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
+  configAttribs.PushBack( 0 );
+#endif // _ARCH_ARM_
+
+  configAttribs.PushBack( EGL_DEPTH_SIZE );
+  configAttribs.PushBack( 24 );
+  configAttribs.PushBack( EGL_STENCIL_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_SAMPLES );
+  configAttribs.PushBack( 4 );
+  configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
+  configAttribs.PushBack( 1 );
+  configAttribs.PushBack( EGL_NONE );
+
+  if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
+  {
+    EGLint error = eglGetError();
+    switch (error)
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR("Display is not an EGL display connection\n");
+        break;
+      }
+      case EGL_BAD_ATTRIBUTE:
+      {
+        DALI_LOG_ERROR("The parameter configAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
+        break;
+      }
+      case EGL_NOT_INITIALIZED:
+      {
+        DALI_LOG_ERROR("Display has not been initialized\n");
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR("The parameter numConfig is NULL\n");
+        break;
+      }
+      default:
+      {
+        DALI_LOG_ERROR("Unknown error.\n");
+      }
+    }
+    DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
+  }
+
+  if ( numConfigs != 1 )
+  {
+    DALI_LOG_ERROR("No configurations found.\n");
+
+    TEST_EGL_ERROR("eglChooseConfig");
+  }
+}
+
+void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
+{
+  DALI_ASSERT_ALWAYS( ( mEglSurface == 0 ) && "EGL surface already exists" );
+
+  mEglNativeWindow = window;
+  mColorDepth = depth;
+  mIsWindow = true;
+
+  // egl choose config
+  ChooseConfig(mIsWindow, mColorDepth);
+
+  mEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
+  TEST_EGL_ERROR("eglCreateWindowSurface");
+
+  DALI_ASSERT_ALWAYS( mEglSurface && "Create window surface failed" );
+}
+
+void EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
+{
+  DALI_ASSERT_ALWAYS( mEglSurface == 0 && "Cannot create more than one instance of surface pixmap" );
+
+  mEglNativePixmap = pixmap;
+  mColorDepth = depth;
+  mIsWindow = false;
+
+  // egl choose config
+  ChooseConfig(mIsWindow, mColorDepth);
+
+  mEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mEglNativePixmap, NULL );
+  TEST_EGL_ERROR("eglCreatePixmapSurface");
+
+  DALI_ASSERT_ALWAYS( mEglSurface && "Create pixmap surface failed" );
+}
+
+bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
+{
+  bool contextLost = false;
+
+  // display connection has not changed, then we can just create a new surface
+  //  the surface is bound to the context, so set the context to null
+  MakeContextNull();
+
+  // destroy the surface
+  DestroySurface();
+
+  // create the EGL surface
+  CreateSurfaceWindow( window, mColorDepth );
+
+  // set the context to be current with the new surface
+  MakeContextCurrent();
+
+  return contextLost;
+}
+
+bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap )
+{
+  bool contextLost = false;
+
+  //  the surface is bound to the context, so set the context to null
+  MakeContextNull();
+
+  // destroy the surface
+  DestroySurface();
+
+  // display connection has not changed, then we can just create a new surface
+  // create the EGL surface
+  CreateSurfacePixmap( pixmap, mColorDepth );
+
+  // set the context to be current with the new surface
+  MakeContextCurrent();
+
+  return contextLost;
+}
+
+EGLDisplay EglImplementation::GetDisplay() const
+{
+  return mEglDisplay;
+}
+
+EGLDisplay EglImplementation::GetContext() const
+{
+  return mEglContext;
+}
+
+EGLConfig EglImplementation::GetConfig() const
+{
+  return mEglConfig;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/event-handler-wl.cpp b/adaptors/wayland/event-handler-wl.cpp
new file mode 100644 (file)
index 0000000..76e6dda
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <events/event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <ecore-wl-render-surface.h>
+#include <cstring>
+
+#include <sys/time.h>
+
+#ifndef DALI_PROFILE_UBUNTU
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif // DALI_PROFILE_UBUNTU
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-manager.h>
+#include <window-render-surface.h>
+#include <clipboard-impl.h>
+#include <key-impl.h>
+#include <physical-keyboard-impl.h>
+#include <style-monitor-impl.h>
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
+Integration::Log::Filter* gClientMessageLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_CLIENT_MESSAGE");
+Integration::Log::Filter* gDragAndDropLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DND");
+Integration::Log::Filter* gImfLogging  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_IMF");
+Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_SELECTION");
+} // unnamed namespace
+#endif
+
+
+namespace
+{
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3;
+
+/**
+ * Ecore_Event_Modifier enums in Ecore_Input.h do not match Ecore_IMF_Keyboard_Modifiers in Ecore_IMF.h.
+ * This function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Modifiers enums.
+ * @param[in] ecoreModifier the Ecore_Event_Modifier input.
+ * @return the Ecore_IMF_Keyboard_Modifiers output.
+ */
+Ecore_IMF_Keyboard_Modifiers EcoreInputModifierToEcoreIMFModifier(unsigned int ecoreModifier)
+{
+   int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
+
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
+   }
+
+   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
+}
+
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+#ifndef DALI_PROFILE_UBUNTU
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE = "db/setting/accessibility/font_name";  // It will be update at vconf-key.h and replaced.
+#endif // DALI_PROFILE_UBUNTU
+
+} // unnamed namespace
+
+// Impl to hide EFL implementation.
+struct EventHandler::Impl
+{
+  // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  Impl( EventHandler* handler, Ecore_Wl_Window* window )
+  : mHandler( handler ),
+    mEcoreEventHandler(),
+    mWindow( window )
+  {
+    // Only register for touch and key events if we have a window
+    if ( window != 0 )
+    {
+      // Register Touch events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_DOWN,  EcoreEventMouseButtonDown, handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_UP,    EcoreEventMouseButtonUp,   handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_MOVE,         EcoreEventMouseButtonMove, handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_OUT,          EcoreEventMouseButtonUp,   handler ) ); // process mouse out event like up event
+
+      // Register Mouse wheel events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_WHEEL,        EcoreEventMouseWheel,      handler ) );
+
+      // Register Key events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,           EcoreEventKeyDown,         handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_UP,             EcoreEventKeyUp,           handler ) );
+
+#ifndef DALI_PROFILE_UBUNTU
+      // Register Vconf notify - font name and size
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontNameChanged, handler );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, handler );
+#endif // DALI_PROFILE_UBUNTU
+    }
+  }
+
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged );
+    vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontNameChanged );
+#endif // DALI_PROFILE_UBUNTU
+
+    for( std::vector<Ecore_Event_Handler*>::iterator iter = mEcoreEventHandler.begin(), endIter = mEcoreEventHandler.end(); iter != endIter; ++iter )
+    {
+      ecore_event_handler_del( *iter );
+    }
+  }
+
+  // Static methods
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Touch Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a touch down is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonDown( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Button *touchEvent( (Ecore_Event_Mouse_Button*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      TouchPoint::State state ( TouchPoint::Down );
+
+      // Check if the buttons field is set and ensure it's the primary touch button.
+      // If this event was triggered by buttons other than the primary button (used for touch), then
+      // just send an interrupted event to Core.
+      if ( touchEvent->buttons && (touchEvent->buttons != PRIMARY_TOUCH_BUTTON_ID ) )
+      {
+        state = TouchPoint::Interrupted;
+      }
+
+      TouchPoint point( touchEvent->multi.device, state, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch up is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonUp( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Button *touchEvent( (Ecore_Event_Mouse_Button*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      TouchPoint point( touchEvent->multi.device, TouchPoint::Up, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch up is received.
+   */
+  static Eina_Bool EcoreEventMouseWheel( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Wheel *mouseWheelEvent( (Ecore_Event_Mouse_Wheel*)event );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT Ecore_Event_Mouse_Wheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent->direction, mouseWheelEvent->modifiers, mouseWheelEvent->x, mouseWheelEvent->y, mouseWheelEvent->z);
+
+    EventHandler* handler( (EventHandler*)data );
+    if ( mouseWheelEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent->direction, mouseWheelEvent->modifiers, Vector2(mouseWheelEvent->x, mouseWheelEvent->y), mouseWheelEvent->z, mouseWheelEvent->timestamp );
+      handler->SendWheelEvent( wheelEvent );
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch motion is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonMove( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Move *touchEvent( (Ecore_Event_Mouse_Move*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      TouchPoint point( touchEvent->multi.device, TouchPoint::Motion, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Key Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a key down is received.
+   */
+  static Eina_Bool EcoreEventKeyDown( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventKeyDown \n" );
+
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Event_Key *keyEvent( (Ecore_Event_Key*)event );
+    bool eventHandled( false );
+
+    // If a device key then skip ecore_imf_context_filter_event.
+    if ( ! KeyLookup::IsDeviceButton( keyEvent->keyname ) )
+    {
+      Ecore_IMF_Context* imfContext = NULL;
+      Dali::ImfManager imfManager( ImfManager::Get() );
+      if ( imfManager )
+      {
+        imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+      }
+
+      if ( imfContext )
+      {
+        // We're consuming key down event so we have to pass to IMF so that it can parse it as well.
+        Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
+        ecoreKeyDownEvent.keyname   = keyEvent->keyname;
+        ecoreKeyDownEvent.key       = keyEvent->key;
+        ecoreKeyDownEvent.string    = keyEvent->string;
+        ecoreKeyDownEvent.compose   = keyEvent->compose;
+        ecoreKeyDownEvent.timestamp = keyEvent->timestamp;
+        ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
+        ecoreKeyDownEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+
+        eventHandled = ecore_imf_context_filter_event( imfContext,
+                                                       ECORE_IMF_EVENT_KEY_DOWN,
+                                                       (Ecore_IMF_Event *) &ecoreKeyDownEvent );
+
+        // If the event has not been handled by IMF then check if we should reset our IMF context
+        if( !eventHandled )
+        {
+          if ( !strcmp( keyEvent->keyname, "Escape"   ) ||
+               !strcmp( keyEvent->keyname, "Return"   ) ||
+               !strcmp( keyEvent->keyname, "KP_Enter" ) )
+          {
+            ecore_imf_context_reset( imfContext );
+          }
+        }
+      }
+    }
+
+    // If the event wasn't handled then we should send a key event.
+    if ( !eventHandled )
+    {
+      if ( keyEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+      {
+        std::string keyName( keyEvent->keyname );
+        std::string keyString( "" );
+        int keyCode = 0/*ecore_x_keysym_keycode_get(keyEvent->keyname)*/;
+        int modifier( keyEvent->modifiers );
+        unsigned long time = keyEvent->timestamp;
+
+        if (!strncmp(keyEvent->keyname, "Keycode-", 8))
+          keyCode = atoi(keyEvent->keyname + 8);
+
+        // Ensure key event string is not NULL as keys like SHIFT have a null string.
+        if ( keyEvent->string )
+        {
+          keyString = keyEvent->string;
+        }
+
+        KeyEvent keyEvent(keyName, keyString, keyCode, modifier, time, KeyEvent::Down);
+        handler->SendEvent( keyEvent );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a key up is received.
+   */
+  static Eina_Bool EcoreEventKeyUp( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventKeyUp \n" );
+
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Event_Key *keyEvent( (Ecore_Event_Key*)event );
+    bool eventHandled( false );
+
+    // Menu, home, back button must skip ecore_imf_context_filter_event.
+    static const char* menuKeyName = KeyLookup::GetKeyName( DALI_KEY_MENU );
+    static const char* homeKeyName = KeyLookup::GetKeyName( DALI_KEY_HOME );
+    static const char* backKeyName = KeyLookup::GetKeyName( DALI_KEY_BACK );
+    if ( ( menuKeyName && strcmp( keyEvent->keyname, menuKeyName ) != 0 ) &&
+         ( homeKeyName && strcmp( keyEvent->keyname, homeKeyName ) != 0 ) &&
+         ( backKeyName && strcmp( keyEvent->keyname, backKeyName ) != 0 ) )
+    {
+      Ecore_IMF_Context* imfContext = NULL;
+      Dali::ImfManager imfManager( ImfManager::Get() );
+      if ( imfManager )
+      {
+        imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+      }
+
+      if ( imfContext )
+      {
+        // We're consuming key up event so we have to pass to IMF so that it can parse it as well.
+        Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
+        ecoreKeyUpEvent.keyname   = keyEvent->keyname;
+        ecoreKeyUpEvent.key       = keyEvent->key;
+        ecoreKeyUpEvent.string    = keyEvent->string;
+        ecoreKeyUpEvent.compose   = keyEvent->compose;
+        ecoreKeyUpEvent.timestamp = keyEvent->timestamp;
+        ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
+        ecoreKeyUpEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+
+        eventHandled = ecore_imf_context_filter_event( imfContext,
+                                                       ECORE_IMF_EVENT_KEY_UP,
+                                                       (Ecore_IMF_Event *) &ecoreKeyUpEvent );
+      }
+    }
+
+    // If the event wasn't handled then we should send a key event.
+    if ( !eventHandled )
+    {
+      if ( keyEvent->window == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+      {
+        std::string keyName( keyEvent->keyname );
+        std::string keyString( "" );
+        int keyCode = 0/*ecore_x_keysym_keycode_get(keyEvent->keyname)*/;
+        int modifier( keyEvent->modifiers );
+        unsigned long time( keyEvent->timestamp );
+
+        if (!strncmp(keyEvent->keyname, "Keycode-", 8))
+          keyCode = atoi(keyEvent->keyname + 8);
+
+        // Ensure key event string is not NULL as keys like SHIFT have a null string.
+        if ( keyEvent->string )
+        {
+          keyString = keyEvent->string;
+        }
+
+        KeyEvent keyEvent(keyName, keyString, keyCode, modifier, time, KeyEvent::Up);
+        handler->SendEvent( keyEvent );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Window Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when the window gains focus.
+   */
+  static Eina_Bool EcoreEventWindowFocusIn( void* data, int type, void* event )
+  {
+    Ecore_Wl_Event_Focus_In* focusInEvent( (Ecore_Wl_Event_Focus_In*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventWindowFocusIn \n" );
+
+    // If the window gains focus and we hid the keyboard then show it again.
+    if ( focusInEvent->win == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT EcoreEventWindowFocusIn - >>WindowFocusGained \n" );
+
+      if ( ImfManager::IsAvailable() /* Only get the ImfManager if it's available as we do not want to create it */ )
+      {
+        Dali::ImfManager imfManager( ImfManager::Get() );
+        if ( imfManager )
+        {
+          ImfManager& imfManagerImpl( ImfManager::GetImplementation( imfManager ) );
+          if( imfManagerImpl.RestoreAfterFocusLost() )
+          {
+            imfManagerImpl.Activate();
+          }
+        }
+      }
+      // No need to connect callbacks as KeyboardStatusChanged will be called.
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window loses focus.
+   */
+  static Eina_Bool EcoreEventWindowFocusOut( void* data, int type, void* event )
+  {
+    Ecore_Wl_Event_Focus_Out* focusOutEvent( (Ecore_Wl_Event_Focus_Out*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventWindowFocusOut \n" );
+
+    // If the window loses focus then hide the keyboard.
+    if ( focusOutEvent->win == (unsigned int)ecore_wl_window_id_get(handler->mImpl->mWindow) )
+    {
+      if ( ImfManager::IsAvailable() /* Only get the ImfManager if it's available as we do not want to create it */ )
+      {
+        Dali::ImfManager imfManager( ImfManager::Get() );
+        if ( imfManager )
+        {
+          ImfManager& imfManagerImpl( ImfManager::GetImplementation( imfManager ) );
+          if( imfManagerImpl.RestoreAfterFocusLost() )
+          {
+            imfManagerImpl.Deactivate();
+          }
+        }
+      }
+
+      // Clipboard don't support that whether clipboard is shown or not. Hide clipboard.
+      Dali::Clipboard clipboard = Clipboard::Get();
+      clipboard.HideClipboard();
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window is damaged.
+   */
+  static Eina_Bool EcoreEventWindowDamaged(void *data, int type, void *event)
+  {
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window properties are changed.
+   * We are only interested in the font change.
+   */
+
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Drag & Drop Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a dragged item enters our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndEnter( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndEnter\n" );
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved within our window.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndPosition( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndPosition\n" );
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item leaves our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndLeave( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndLeave\n" );
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the dragged item is dropped within our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndDrop( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndDrop\n" );
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved from our window and the target window has done processing it.
+   * This is when items are dragged FROM our window.
+   */
+  static Eina_Bool EcoreEventDndFinished( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndFinished\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved from our window and the target window has sent us a status.
+   * This is when items are dragged FROM our window.
+   */
+  static Eina_Bool EcoreEventDndStatus( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndStatus\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the client messages (i.e. the accessibility events) are received.
+   */
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the source window notifies us the content in clipboard is selected.
+   */
+  static Eina_Bool EcoreEventSelectionClear( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventSelectionClear\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the source window sends us about the selected content.
+   * For example, when dragged items are dragged INTO our window or when items are selected in the clipboard.
+   */
+  static Eina_Bool EcoreEventSelectionNotify( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventSelectionNotify\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Font Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   * Called when a font name is changed.
+   */
+  static void VconfNotifyFontNameChanged( keynode_t* node, void* data )
+  {
+    EventHandler* handler = static_cast<EventHandler*>( data );
+    handler->SendEvent( StyleChange::DEFAULT_FONT_CHANGE );
+  }
+
+  /**
+   * Called when a font size is changed.
+   */
+  static void VconfNotifyFontSizeChanged( keynode_t* node, void* data )
+  {
+    EventHandler* handler = static_cast<EventHandler*>( data );
+    handler->SendEvent( StyleChange::DEFAULT_FONT_SIZE_CHANGE );
+  }
+
+  // Data
+  EventHandler* mHandler;
+  std::vector<Ecore_Event_Handler*> mEcoreEventHandler;
+  Ecore_Wl_Window* mWindow;
+};
+
+EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector )
+: mCoreEventInterface(coreEventInterface),
+  mGestureManager( gestureManager ),
+  mStyleMonitor( StyleMonitor::Get() ),
+  mDamageObserver( damageObserver ),
+  mRotationObserver( NULL ),
+  mDragAndDropDetector( dndDetector ),
+  mAccessibilityAdaptor( AccessibilityAdaptor::Get() ),
+  mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
+  mClipboard(Clipboard::Get()),
+  mImpl( NULL )
+{
+  Ecore_Wl_Window* window = 0;
+
+  // this code only works with the Ecore RenderSurface so need to downcast
+  ECore::WindowRenderSurface* ecoreSurface = dynamic_cast< ECore::WindowRenderSurface* >( surface );
+  if( ecoreSurface )
+  {
+    window = ecoreSurface->GetWlWindow();
+  }
+
+  mImpl = new Impl(this, window);
+}
+
+EventHandler::~EventHandler()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+  }
+
+  mGestureManager.Stop();
+}
+
+void EventHandler::SendEvent(TouchPoint& point, unsigned long timeStamp)
+{
+  if(timeStamp < 1)
+  {
+    timeStamp = GetCurrentMilliSeconds();
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if(type != Integration::TouchEventCombiner::DispatchNone )
+  {
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.deviceId, point.state, point.local.x, point.local.y);
+
+    // First the touch and/or hover event & related gesture events are queued
+    if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( touchEvent );
+      mGestureManager.SendEvent(touchEvent);
+    }
+
+    if(type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( hoverEvent );
+    }
+
+    // Next the events are processed with a single call into Core
+    mCoreEventInterface.ProcessCoreEvents();
+  }
+}
+
+void EventHandler::SendEvent(KeyEvent& keyEvent)
+{
+  Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
+  if ( physicalKeyboard )
+  {
+    if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ) )
+    {
+      GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
+    }
+  }
+
+  // Create KeyEvent and send to Core.
+  Integration::KeyEvent event(keyEvent.keyPressedName, keyEvent.keyPressed, keyEvent.keyCode,
+  keyEvent.keyModifier, keyEvent.time, static_cast<Integration::KeyEvent::State>(keyEvent.state));
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendWheelEvent( WheelEvent& wheelEvent )
+{
+  // Create WheelEvent and send to Core.
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendEvent( StyleChange::Type styleChange )
+{
+  DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
+  GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
+}
+
+void EventHandler::SendEvent( const DamageArea& area )
+{
+  mDamageObserver.OnDamaged( area );
+}
+
+void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationPrepare( event );
+  }
+}
+
+void EventHandler::SendRotationRequestEvent( )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationRequest( );
+  }
+}
+
+void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)
+{
+  SendEvent(point, timeStamp);
+}
+
+void EventHandler::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  SendWheelEvent( wheelEvent );
+}
+
+void EventHandler::FeedKeyEvent( KeyEvent& event )
+{
+  SendEvent( event );
+}
+
+void EventHandler::FeedEvent( Integration::Event& event )
+{
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Reset()
+{
+  mCombiner.Reset();
+
+  // Any touch listeners should be told of the interruption.
+  Integration::TouchEvent event;
+  TouchPoint point(0, TouchPoint::Interrupted, 0, 0);
+  event.AddPoint( point );
+
+  // First the touch event & related gesture events are queued
+  mCoreEventInterface.QueueCoreEvent( event );
+  mGestureManager.SendEvent( event );
+
+  // Next the events are processed with a single call into Core
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Pause()
+{
+  mPaused = true;
+  Reset();
+}
+
+void EventHandler::Resume()
+{
+  mPaused = false;
+  Reset();
+}
+
+void EventHandler::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
+{
+  mDragAndDropDetector = detector;
+}
+
+void EventHandler::SetRotationObserver( RotationObserver* observer )
+{
+  mRotationObserver = observer;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/file.list b/adaptors/wayland/file.list
new file mode 100644 (file)
index 0000000..df6cfc0
--- /dev/null
@@ -0,0 +1,23 @@
+# wayland
+
+adaptor_wayland_tizen_internal_src_files = \
+  $(adaptor_wayland_dir)/accessibility-adaptor-impl-wl.cpp \
+  $(adaptor_wayland_dir)/clipboard-impl-wl.cpp \
+  $(adaptor_wayland_dir)/display-connection-impl-wl.cpp \
+  $(adaptor_wayland_dir)/framework-wl.cpp \
+  $(adaptor_wayland_dir)/imf-manager-impl-wl.cpp \
+  $(adaptor_wayland_dir)/native-image-source-impl-wl.cpp \
+  $(adaptor_wayland_dir)/server-connection-wl.cpp \
+  $(adaptor_wayland_dir)/virtual-keyboard-impl-wl.cpp \
+  $(adaptor_wayland_dir)/window-impl-wl.cpp \
+  $(adaptor_wayland_dir)/event-handler-wl.cpp \
+  $(adaptor_wayland_dir)/egl-implementation-wl.cpp \
+  $(adaptor_wayland_dir)/pixmap-render-surface-wl.cpp \
+  $(adaptor_wayland_dir)/ecore-wl-render-surface.cpp \
+  $(adaptor_wayland_dir)/window-render-surface-wl.cpp \
+  $(adaptor_wayland_dir)/key-mapping-wl.cpp \
+  $(adaptor_wayland_dir)/key-grab-wl.cpp
+
+adaptor_wayland_tizen_common_internal_default_profile_src_files = \
+  $(adaptor_wayland_dir)/ecore-wl-render-surface-factory.cpp \
+  $(adaptor_wayland_dir)/system-settings-wl.cpp
diff --git a/adaptors/wayland/framework-wl.cpp b/adaptors/wayland/framework-wl.cpp
new file mode 100644 (file)
index 0000000..bad2eb0
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "framework.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void Framework::InitThreads()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/imf-manager-impl-wl.cpp b/adaptors/wayland/imf-manager-impl-wl.cpp
new file mode 100644 (file)
index 0000000..84bbdd2
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <imf-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <window-render-surface.h>
+#include <adaptor-impl.h>
+#include <singleton-service-impl.h>
+#include <virtual-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+BaseHandle Create()
+{
+  return ImfManager::Get();
+}
+
+TypeRegistration IMF_MANAGER_TYPE( typeid(Dali::ImfManager), typeid(Dali::BaseHandle), Create );
+
+} // unnamed namespace
+
+bool ImfManager::IsAvailable()
+{
+  return false;
+}
+
+Dali::ImfManager ImfManager::Get()
+{
+  // Return empty handle as not supported
+  return Dali::ImfManager();
+}
+
+ImfManager::~ImfManager()
+{
+}
+
+void ImfManager::DeleteContext()
+{
+}
+
+void ImfManager::ConnectCallbacks()
+{
+}
+
+void ImfManager::DisconnectCallbacks()
+{
+}
+
+void ImfManager::Activate()
+{
+}
+
+void ImfManager::Deactivate()
+{
+}
+
+void ImfManager::Reset()
+{
+}
+
+Ecore_IMF_Context* ImfManager::GetContext()
+{
+  return mIMFContext;
+}
+
+bool ImfManager::RestoreAfterFocusLost() const
+{
+  return mRestoreAfterFocusLost;
+}
+
+void ImfManager::SetRestoreAfterFocusLost( bool toggle )
+{
+  mRestoreAfterFocusLost = toggle;
+}
+
+void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
+{
+}
+
+void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
+{
+}
+
+Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
+{
+  return EINA_TRUE;
+}
+
+void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+{
+}
+
+void ImfManager::NotifyCursorPosition()
+{
+}
+
+int ImfManager::GetCursorPosition()
+{
+  return mIMFCursorPosition;
+}
+
+void ImfManager::SetCursorPosition( unsigned int cursorPosition )
+{
+  mIMFCursorPosition = ( int )cursorPosition;
+}
+
+void ImfManager::SetSurroundingText( std::string text )
+{
+  mSurroundingText = text;
+}
+
+std::string ImfManager::GetSurroundingText()
+{
+  return mSurroundingText;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/adaptors/wayland/imf-manager-impl.h b/adaptors/wayland/imf-manager-impl.h
new file mode 100644 (file)
index 0000000..07ec6e3
--- /dev/null
@@ -0,0 +1,225 @@
+#ifndef __DALI_INTERNAL_IMF_MANAGER_H
+#define __DALI_INTERNAL_IMF_MANAGER_H
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_IMF.h>
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/events/key-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <imf-manager.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class ImfManager : public Dali::BaseObject
+{
+public:
+  typedef Dali::ImfManager::ImfManagerSignalType ImfManagerSignalType;
+  typedef Dali::ImfManager::ImfEventSignalType ImfEventSignalType;
+
+public:
+
+  /**
+   * Check whether the ImfManager is available.
+   * @return true if available, false otherwise
+   */
+  static bool IsAvailable();
+
+  /**
+   * Get the IMF manager instance, it creates the instance if it has not already been created.
+   * Internally, a check should be made using IsAvailable() before this is called as we do not want
+   * to create an instance if not needed by applications.
+   * @see IsAvailable()
+   */
+  static Dali::ImfManager Get();
+
+  /**
+   * Connect Callbacks required for IMF.
+   * If you don't connect imf callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit and DeleteSurrounding.
+   */
+  void ConnectCallbacks();
+
+  /**
+   * Disconnect Callbacks attached to imf context.
+   */
+  void DisconnectCallbacks();
+
+  /**
+   * @copydoc Dali::ImfManager::Activate()
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::ImfManager::Deactivate()
+   */
+  void Deactivate();
+
+  /**
+   * @copydoc Dali::ImfManager::Reset()
+   */
+  void Reset();
+
+  /**
+   * @copydoc Dali::ImfManager::GetContext()
+   */
+  Ecore_IMF_Context* GetContext();
+
+  /**
+   * @copydoc Dali::ImfManager::RestoreAfterFocusLost()
+   */
+  bool RestoreAfterFocusLost() const;
+
+  /**
+   * @copydoc Dali::ImfManager::SetRestoreAfterFocusLost()
+   */
+  void SetRestoreAfterFocusLost( bool toggle );
+
+  /**
+   * @copydoc Dali::ImfManager::PreEditChanged()
+   */
+  void PreEditChanged( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  void CommitReceived( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  Eina_Bool RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition );
+
+  /**
+   * @copydoc Dali::ImfManager::DeleteSurrounding()
+   */
+  void DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  // Cursor related
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  void NotifyCursorPosition();
+
+  /**
+   * @copydoc Dali::ImfManager::GetCursorPosition()
+   */
+  int GetCursorPosition();
+
+  /**
+   * @copydoc Dali::ImfManager::SetCursorPosition()
+   */
+  void SetCursorPosition( unsigned int cursorPosition );
+
+  /**
+   * @copydoc Dali::ImfManager::SetSurroundingText()
+   */
+  void SetSurroundingText( std::string text );
+
+  /**
+   * @copydoc Dali::ImfManager::GetSurroundingText()
+   */
+  std::string GetSurroundingText();
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::ImfManager::ActivatedSignal()
+   */
+  ImfManagerSignalType& ActivatedSignal() { return mActivatedSignal; }
+
+  /**
+   * @copydoc Dali::ImfManager::EventReceivedSignal()
+   */
+  ImfEventSignalType& EventReceivedSignal() { return mEventSignal; }
+
+protected:
+
+  /**
+   * Destructor.
+   */
+  virtual ~ImfManager();
+
+private:
+  /**
+   * @copydoc Dali::ImfManager::DeleteContext()
+   */
+  void DeleteContext();
+
+private:
+  // Undefined
+  ImfManager( const ImfManager& );
+  ImfManager& operator=( ImfManager& );
+
+private:
+  Ecore_IMF_Context* mIMFContext;
+  int mIMFCursorPosition;
+  std::string mSurroundingText;
+
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
+
+  std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
+
+  ImfManagerSignalType      mActivatedSignal;
+  ImfEventSignalType        mEventSignal;
+
+public:
+
+inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
+{
+  DALI_ASSERT_ALWAYS( imfManager && "ImfManager handle is empty" );
+
+  BaseObject& handle = imfManager.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::ImfManager&>(handle);
+}
+
+inline static const  Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
+{
+  DALI_ASSERT_ALWAYS( imfManager && "ImfManager handle is empty" );
+
+  const BaseObject& handle = imfManager.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::ImfManager&>(handle);
+}
+
+};
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_IMF_MANAGER_H
diff --git a/adaptors/wayland/key-grab-wl.cpp b/adaptors/wayland/key-grab-wl.cpp
new file mode 100644 (file)
index 0000000..89deb11
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <key-grab.h>
+
+// EXTERNAL INCLUDES
+#include <Ecore_Wayland.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <window.h>
+#include <key-impl.h>
+#include <iostream>
+
+// keycode-related code
+#include "ecore_wl_private.h"
+
+using namespace std;
+
+// keycode-related code
+namespace
+{
+
+const int KEYCODE_BUFFER_SIZE = 5;
+
+typedef struct _keycode_map{
+    xkb_keysym_t keysym;
+    xkb_keycode_t *keycodes;
+    int nkeycodes;
+}keycode_map;
+
+static void find_keycode( struct xkb_keymap *keymap, xkb_keycode_t key, void *data )
+{
+   keycode_map *found_keycodes = (keycode_map *)data;
+   xkb_keysym_t keysym = found_keycodes->keysym;
+   int nsyms = 0;
+   const xkb_keysym_t *syms_out = NULL;
+  
+   nsyms = xkb_keymap_key_get_syms_by_level(keymap, key, 0, 0, &syms_out);
+   if( nsyms && syms_out )
+   {
+     if( *syms_out == keysym )
+     {
+       found_keycodes->nkeycodes++;
+       found_keycodes->keycodes = static_cast<xkb_keycode_t*>(realloc( found_keycodes->keycodes, sizeof(int)*found_keycodes->nkeycodes ));
+       found_keycodes->keycodes[found_keycodes->nkeycodes-1] = key;
+     }
+   }
+}
+
+int xkb_keycode_from_keysym( struct xkb_keymap *keymap, xkb_keysym_t keysym, xkb_keycode_t **keycodes )
+{
+  keycode_map found_keycodes = {0,};
+  found_keycodes.keysym = keysym;
+  xkb_keymap_key_for_each( keymap, find_keycode, &found_keycodes );
+
+  *keycodes = found_keycodes.keycodes;
+  return found_keycodes.nkeycodes;
+}
+
+bool keycode_from_keyname( const char* keyname, char* keycode_buffer )
+{
+  xkb_keysym_t keysym = xkb_keysym_from_name( keyname, XKB_KEYSYM_NO_FLAGS );
+
+  int nkeycodes = 0; // num of keycodes mapping with keysym
+  xkb_keycode_t *keycodes = NULL; // keycodes list
+  nkeycodes = xkb_keycode_from_keysym( ecore_wl_input_get()->xkb.keymap, keysym, &keycodes );
+  if( nkeycodes > 0)
+  {
+    snprintf( keycode_buffer, KEYCODE_BUFFER_SIZE, "%d", keycodes[0] );
+    return true;
+  }
+  else
+  {
+    return false;
+  }
+  free(keycodes);
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace KeyGrab
+{
+
+bool GrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  return GrabKey( window, daliKey, TOPMOST);
+}
+
+bool UngrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  return UngrabKey( window, daliKey );
+}
+
+bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode )
+{
+  Ecore_Wl_Window_Keygrab_Mode wlGrabMode;
+  if( grabMode == TOPMOST )
+  {
+    wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_TOPMOST;
+  }
+  else if( grabMode == SHARED )
+  {
+    wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_SHARED;
+  }
+  else if( grabMode == OVERRIDE_EXCLUSIVE )
+  {
+    wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
+  }
+  else if( grabMode == EXCLUSIVE )
+  {
+    wlGrabMode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+  }
+  else
+  {
+    return false;
+  }
+
+  // keycode-related code
+  char keycode[KEYCODE_BUFFER_SIZE];
+  if( !keycode_from_keyname( Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ), keycode ) )
+  {
+    DALI_LOG_WARNING( "Unable to get keycode from keyname %s.\n", Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ) );
+    return false;
+  }
+  return ecore_wl_window_keygrab_set( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ),
+                                      keycode,
+                                      0, 0, 0, wlGrabMode );
+
+  // Currently the 2nd parameter of ecore_wl_window_keygrab_set means keycode, but its meaning will be changed to keyname later.
+  // Once changed, we can remove all "keycode-related code" and just uncomment below line and
+  // also can remove following files:
+  // ecore_wl_private.h, tizen-extension-client-protocol.h, tizen-policy-client-protocol.h
+
+  //return ecore_wl_window_keygrab_set( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ),
+                                      //Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ),
+                                      //0, 0, 0, wlGrabMode );
+}
+
+bool UngrabKey( Window window, Dali::KEY daliKey )
+{
+  // keycode-related code
+  char keycode[KEYCODE_BUFFER_SIZE];
+  if( !keycode_from_keyname( Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ), keycode ) )
+  {
+    DALI_LOG_WARNING( "Unable to get keycode from keyname %s.\n", Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ) );
+    return false;
+  }
+  return ecore_wl_window_keygrab_unset( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ),
+                                      keycode,
+                                      0, 0 );
+
+  // Currently the 2nd parameter of ecore_wl_window_keygrab_set means keycode, but its meaning will be changed to keyname later.
+  // Once changed, we can remove all "keycode-related code" and just uncomment below line and
+  // also can remove following files:
+  // ecore_wl_private.h, tizen-extension-client-protocol.h, tizen-policy-client-protocol.h
+
+  //return ecore_wl_window_keygrab_unset( AnyCast<Ecore_Wl_Window*>( window.GetNativeHandle() ),
+                                      //Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey ),
+                                      //0, 0 );
+}
+
+} // namespace KeyGrab
+
+} // namespace Dali
+
+
diff --git a/adaptors/wayland/key-mapping-wl.cpp b/adaptors/wayland/key-mapping-wl.cpp
new file mode 100644 (file)
index 0000000..912ea8a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "key-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,          false },
+  { "Menu",                  DALI_KEY_MENU,            false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,      false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,     false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable))/ (sizeof(KeyLookup));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/keyrouter-client-protocol.h b/adaptors/wayland/keyrouter-client-protocol.h
new file mode 100644 (file)
index 0000000..7181278
--- /dev/null
@@ -0,0 +1,167 @@
+/* 
+ * Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
+ * Contact: Sung-Jin Park (sj76.park@samsung.com),
+ * Jeonghyun Kang (jhyuni.kang@samsung.com)
+ * 
+ * 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, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ * 
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#ifndef KEYROUTER_CLIENT_PROTOCOL_H
+#define KEYROUTER_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_keyrouter;
+
+extern const struct wl_interface wl_keyrouter_interface;
+
+#ifndef WL_KEYROUTER_ERROR_ENUM
+#define WL_KEYROUTER_ERROR_ENUM
+enum wl_keyrouter_error {
+       WL_KEYROUTER_ERROR_NONE = 0,
+       WL_KEYROUTER_ERROR_INVALID_SURFACE = 1,
+       WL_KEYROUTER_ERROR_INVALID_KEY = 2,
+       WL_KEYROUTER_ERROR_INVALID_MODE = 3,
+       WL_KEYROUTER_ERROR_GRABBED_ALREADY = 4,
+       WL_KEYROUTER_ERROR_NO_PERMISSION = 5,
+       WL_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES = 6,
+};
+#endif /* WL_KEYROUTER_ERROR_ENUM */
+
+#ifndef WL_KEYROUTER_MODE_ENUM
+#define WL_KEYROUTER_MODE_ENUM
+/**
+ * wl_keyrouter_mode - mode for a key grab
+ * @WL_KEYROUTER_MODE_NONE: none
+ * @WL_KEYROUTER_MODE_SHARED: mode to get a key grab with the other
+ *     client surfaces when the focused client surface gets the key
+ * @WL_KEYROUTER_MODE_TOPMOST: mode to get a key grab when the client
+ *     surface is the top most surface
+ * @WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE: mode to get a key grab
+ *     exclusively, overridably regardless of the order in the surface stack
+ * @WL_KEYROUTER_MODE_EXCLUSIVE: mode to get a key grab exclusively
+ *     regardless of the order in surface stack
+ *
+ * This value is used to set a mode for a key grab. With this mode and
+ * the order of the surface between surfaces' stack, the compositor will
+ * determine the destination client surface.
+ */
+enum wl_keyrouter_mode {
+       WL_KEYROUTER_MODE_NONE = 0,
+       WL_KEYROUTER_MODE_SHARED = 1,
+       WL_KEYROUTER_MODE_TOPMOST = 2,
+       WL_KEYROUTER_MODE_OVERRIDABLE_EXCLUSIVE = 3,
+       WL_KEYROUTER_MODE_EXCLUSIVE = 4,
+};
+#endif /* WL_KEYROUTER_MODE_ENUM */
+
+/**
+ * wl_keyrouter - an interface to set each focus for each key
+ * @keygrab_notify: (none)
+ *
+ * In tradition, all the keys in a keyboard and a device on which some
+ * keys are attached will be sent to focus surface by default. Currently
+ * it's possible to set up each focus for each key in a keyboard and a
+ * device. Therefore, by setting a key grab for a surface, the owner of the
+ * surface will get the key event when it has the key grab for the key.
+ */
+struct wl_keyrouter_listener {
+       /**
+        * keygrab_notify - (none)
+        * @surface: (none)
+        * @key: (none)
+        * @mode: (none)
+        * @error: (none)
+        */
+       void (*keygrab_notify)(void *data,
+                              struct wl_keyrouter *wl_keyrouter,
+                              struct wl_surface *surface,
+                              uint32_t key,
+                              uint32_t mode,
+                              uint32_t error);
+};
+
+static inline int
+wl_keyrouter_add_listener(struct wl_keyrouter *wl_keyrouter,
+                         const struct wl_keyrouter_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) wl_keyrouter,
+                                    (void (**)(void)) listener, data);
+}
+
+#define WL_KEYROUTER_SET_KEYGRAB       0
+#define WL_KEYROUTER_UNSET_KEYGRAB     1
+#define WL_KEYROUTER_GET_KEYGRAB_STATUS        2
+
+static inline void
+wl_keyrouter_set_user_data(struct wl_keyrouter *wl_keyrouter, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) wl_keyrouter, user_data);
+}
+
+static inline void *
+wl_keyrouter_get_user_data(struct wl_keyrouter *wl_keyrouter)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) wl_keyrouter);
+}
+
+static inline void
+wl_keyrouter_destroy(struct wl_keyrouter *wl_keyrouter)
+{
+       wl_proxy_destroy((struct wl_proxy *) wl_keyrouter);
+}
+
+static inline void
+wl_keyrouter_set_keygrab(struct wl_keyrouter *wl_keyrouter, struct wl_surface *surface, uint32_t key, uint32_t mode)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_keyrouter,
+                        WL_KEYROUTER_SET_KEYGRAB, surface, key, mode);
+}
+
+static inline void
+wl_keyrouter_unset_keygrab(struct wl_keyrouter *wl_keyrouter, struct wl_surface *surface, uint32_t key)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_keyrouter,
+                        WL_KEYROUTER_UNSET_KEYGRAB, surface, key);
+}
+
+static inline void
+wl_keyrouter_get_keygrab_status(struct wl_keyrouter *wl_keyrouter, struct wl_surface *surface, uint32_t key)
+{
+       wl_proxy_marshal((struct wl_proxy *) wl_keyrouter,
+                        WL_KEYROUTER_GET_KEYGRAB_STATUS, surface, key);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/adaptors/wayland/native-image-source-impl-wl.cpp b/adaptors/wayland/native-image-source-impl-wl.cpp
new file mode 100644 (file)
index 0000000..5260e30
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "native-image-source-impl.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <gl/egl-image-extensions.h>
+#include <gl/egl-factory.h>
+#include <adaptor-impl.h>
+#include <render-surface.h>
+
+// Allow this to be encoded and saved:
+#include <platform-abstractions/tizen/resource-loader/resource-loader.h>
+#include <bitmap-saver.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+using Dali::Integration::PixelBuffer;
+
+NativeImageSource* NativeImageSource::New(unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSource* image = new NativeImageSource( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  // 2nd phase construction
+  if(image) //< Defensive in case we ever compile without exceptions.
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnPixmap( true ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglImageExtensions( NULL )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+  EglFactory& eglFactory = Adaptor::GetImplementation( Adaptor::Get() ).GetEGLFactory();
+  mEglImageExtensions = eglFactory.GetImageExtensions();
+  SetBlending( mColorDepth );
+
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+}
+
+void NativeImageSource::Initialize()
+{
+}
+
+NativeImageSource::~NativeImageSource()
+{
+}
+
+Any NativeImageSource::GetNativeImageSource() const
+{
+  DALI_ASSERT_ALWAYS( false && "NativeImageSource::GetNativeImageSource() is not supported for Wayland." );
+  return Any();
+}
+
+bool NativeImageSource::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+    return false;
+}
+
+bool NativeImageSource::EncodeToFile(const std::string& filename) const
+{
+  std::vector< unsigned char > pixbuf;
+  unsigned int width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if(GetPixels(pixbuf, width, height, pixelFormat))
+  {
+    return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
+  }
+  return false;
+}
+
+bool NativeImageSource::GlExtensionCreate()
+{
+    return false;
+}
+
+void NativeImageSource::GlExtensionDestroy()
+{
+  mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
+
+  mEglImageKHR = NULL;
+}
+
+unsigned int NativeImageSource::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
+
+  return 0;
+}
+
+void NativeImageSource::SetBlending(Dali::NativeImageSource::ColorDepth depth)
+{
+  switch (depth)
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_16: //Pixel::RGB565
+    case Dali::NativeImageSource::COLOR_DEPTH_24: // Pixel::RGB888
+    {
+      mBlendingRequired = false;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8: //Pixel::A8
+    case Dali::NativeImageSource::COLOR_DEPTH_32: // Pixel::RGBA8888
+    {
+      mBlendingRequired = true;
+      break;
+    }
+    default:
+    {
+      DALI_ASSERT_DEBUG(0 && "unknown color enum");
+    }
+  }
+}
+
+void NativeImageSource::GetPixmapDetails()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/native-image-source-impl.h b/adaptors/wayland/native-image-source-impl.h
new file mode 100644 (file)
index 0000000..5b756dd
--- /dev/null
@@ -0,0 +1,164 @@
+#ifndef __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
+#define __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <native-image-source.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] depth color depth of the image
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSource* New( unsigned int width,
+                          unsigned int height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource );
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSource();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  unsigned int GetWidth() const
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  unsigned int GetHeight() const
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const
+  {
+    return mBlendingRequired;
+  }
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  NativeImageSource( unsigned int width,
+              unsigned  int height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource );
+
+  /**
+   * 2nd phase construction.
+   */
+  void Initialize();
+
+  /**
+   * Decide whether blending is required based on the color depth.
+   * @param depth the PixelImage depth enum
+   */
+  void SetBlending(Dali::NativeImageSource::ColorDepth depth);
+
+  /**
+   * Given an existing pixmap, the function uses X to find out
+   * the width, heigth and depth of that pixmap.
+   */
+  void GetPixmapDetails();
+
+private:
+
+  unsigned int mWidth;                        ///< pixmap width
+  unsigned int mHeight;                       ///< pixmap heights
+  bool mOwnPixmap;                            ///< Whether we created pixmap or not
+  bool mBlendingRequired;                      ///< Whether blending is required
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of pixmap
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
diff --git a/adaptors/wayland/pixmap-render-surface-wl.cpp b/adaptors/wayland/pixmap-render-surface-wl.cpp
new file mode 100644 (file)
index 0000000..cc76c24
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "pixmap-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <ecore-wl-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+#include <base/display-connection.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gRenderSurfaceLogFilter;
+#endif
+
+namespace ECore
+{
+
+PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
+                                         Any surface,
+                                         const std::string& name,
+                                         bool isTransparent)
+: EcoreWlRenderSurface( positionSize, surface, name, isTransparent )
+{
+  Init( surface );
+}
+
+PixmapRenderSurface::~PixmapRenderSurface()
+{
+  // release the surface if we own one
+  if( mOwnSurface )
+  {
+    // if we did create the pixmap, delete the pixmap
+    DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", mX11Pixmap );
+  }
+}
+
+Ecore_Wl_Window* PixmapRenderSurface::GetDrawable()
+{
+  return NULL;
+}
+
+Any PixmapRenderSurface::GetSurface()
+{
+  return Any( NULL );
+}
+
+void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+
+  eglImpl.ChooseConfig(false, mColorDepth);
+}
+
+void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  // create the EGL surface
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  // FIXME
+}
+
+void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+  eglImpl.DestroySurface();
+}
+
+bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  // a new surface for the new pixmap
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  // FIXME
+  return false;
+}
+
+void PixmapRenderSurface::StartRender()
+{
+  // FIXME
+}
+
+bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
+{
+  // nothing to do for pixmaps
+  return true;
+}
+
+void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
+{
+  // flush gl instruction queue
+  glAbstraction.Flush();
+
+ // create damage for client applications which wish to know the update timing
+  if( mRenderNotification )
+  {
+    // use notification trigger
+    // Tell the event-thread to render the pixmap
+    mRenderNotification->Trigger();
+  }
+  else
+  {
+    // FIXME
+  }
+
+  // Do render synchronisation
+  // AcquireLock( replacingSurface ? SYNC_MODE_NONE : SYNC_MODE_WAIT );
+}
+
+void PixmapRenderSurface::StopRender()
+{
+  // FIXME
+}
+
+void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+  // Nothing to do
+}
+
+void PixmapRenderSurface::CreateWlRenderable()
+{
+  // check we're creating one with a valid size
+  DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
+
+  // FIXME
+}
+
+void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
+{
+  // FIXME
+}
+
+void PixmapRenderSurface::SetSyncMode( SyncMode syncMode )
+{
+  // FIXME
+}
+
+void PixmapRenderSurface::AcquireLock()
+{
+  // FIXME
+}
+
+void PixmapRenderSurface::ReleaseLock()
+{
+  // FIXME
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/wayland/server-connection-wl.cpp b/adaptors/wayland/server-connection-wl.cpp
new file mode 100644 (file)
index 0000000..76376c3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "server-connection.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gIndicatorLogFilter;
+#endif
+
+
+ServerConnection::ServerConnection(
+  const char*                 serviceName,
+  int                         serviceNumber,
+  bool                        isSystem,
+  ServerConnection::Observer* observer)
+
+: mConnected(false),
+  mObserver(observer)
+{
+  ecore_ipc_init();
+  mService.name = eina_stringshare_add(serviceName);
+  mService.num = serviceNumber;
+  mService.isSystem = isSystem;
+
+  DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "ServerConnection: Connecting to %s %d\n", mService.name, mService.num );
+
+  mIpcServer = NULL;
+
+  if( !mIpcServer )
+  {
+    ecore_ipc_shutdown();
+  }
+  else
+  {
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_ADD,
+                                                     &ServerConnection::IpcServerAdd,
+                                                     this ) );
+
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_DEL,
+                                                     &ServerConnection::IpcServerDel,
+                                                     this ) );
+
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_DATA,
+                                                     &ServerConnection::IpcServerData,
+                                                     this));
+
+    mConnected = true;
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/wayland/system-settings-wl.cpp b/adaptors/wayland/system-settings-wl.cpp
new file mode 100644 (file)
index 0000000..54e7809
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "system-settings.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/tizen-extension-client-protocol.h b/adaptors/wayland/tizen-extension-client-protocol.h
new file mode 100644 (file)
index 0000000..d84dc40
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef TIZEN_EXTENSION_CLIENT_PROTOCOL_H
+#define TIZEN_EXTENSION_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct tizen_resource;
+struct tizen_surface_extension;
+struct wl_surface;
+
+extern const struct wl_interface tizen_resource_interface;
+extern const struct wl_interface tizen_surface_extension_interface;
+extern const struct wl_interface wl_surface_interface;
+
+struct tizen_resource_listener {
+       /**
+        * resource_id - (none)
+        * @id: (none)
+        */
+       void (*resource_id)(void *data,
+                           struct tizen_resource *tizen_resource,
+                           uint32_t id);
+};
+
+static inline int
+tizen_resource_add_listener(struct tizen_resource *tizen_resource,
+                           const struct tizen_resource_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) tizen_resource,
+                                    (void (**)(void)) listener, data);
+}
+
+#define TIZEN_RESOURCE_DESTROY 0
+
+static inline void
+tizen_resource_set_user_data(struct tizen_resource *tizen_resource, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) tizen_resource, user_data);
+}
+
+static inline void *
+tizen_resource_get_user_data(struct tizen_resource *tizen_resource)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) tizen_resource);
+}
+
+static inline void
+tizen_resource_destroy(struct tizen_resource *tizen_resource)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_resource,
+                        TIZEN_RESOURCE_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) tizen_resource);
+}
+
+#define TIZEN_SURFACE_EXTENSION_GET_TIZEN_RESOURCE     0
+
+static inline void
+tizen_surface_extension_set_user_data(struct tizen_surface_extension *tizen_surface_extension, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) tizen_surface_extension, user_data);
+}
+
+static inline void *
+tizen_surface_extension_get_user_data(struct tizen_surface_extension *tizen_surface_extension)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) tizen_surface_extension);
+}
+
+static inline void
+tizen_surface_extension_destroy(struct tizen_surface_extension *tizen_surface_extension)
+{
+       wl_proxy_destroy((struct wl_proxy *) tizen_surface_extension);
+}
+
+static inline struct tizen_resource *
+tizen_surface_extension_get_tizen_resource(struct tizen_surface_extension *tizen_surface_extension, struct wl_surface *surface)
+{
+       struct wl_proxy *id;
+
+       id = wl_proxy_marshal_constructor((struct wl_proxy *) tizen_surface_extension,
+                        TIZEN_SURFACE_EXTENSION_GET_TIZEN_RESOURCE, &tizen_resource_interface, NULL, surface);
+
+       return (struct tizen_resource *) id;
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/adaptors/wayland/tizen-policy-client-protocol.h b/adaptors/wayland/tizen-policy-client-protocol.h
new file mode 100644 (file)
index 0000000..8a4113b
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef TIZEN_POLICY_CLIENT_PROTOCOL_H
+#define TIZEN_POLICY_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct tizen_policy;
+struct tizen_visibility;
+struct wl_surface;
+
+extern const struct wl_interface tizen_policy_interface;
+extern const struct wl_interface tizen_visibility_interface;
+extern const struct wl_interface wl_surface_interface;
+
+#define TIZEN_POLICY_GET_VISIBILITY    0
+#define TIZEN_POLICY_ACTIVATE  1
+#define TIZEN_POLICY_POSITION_SET      2
+#define TIZEN_POLICY_FOCUS_SKIP_SET    3
+#define TIZEN_POLICY_FOCUS_SKIP_UNSET  4
+
+static inline void
+tizen_policy_set_user_data(struct tizen_policy *tizen_policy, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) tizen_policy, user_data);
+}
+
+static inline void *
+tizen_policy_get_user_data(struct tizen_policy *tizen_policy)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) tizen_policy);
+}
+
+static inline void
+tizen_policy_destroy(struct tizen_policy *tizen_policy)
+{
+       wl_proxy_destroy((struct wl_proxy *) tizen_policy);
+}
+
+static inline struct tizen_visibility *
+tizen_policy_get_visibility(struct tizen_policy *tizen_policy, struct wl_surface *surface)
+{
+       struct wl_proxy *id;
+
+       id = wl_proxy_marshal_constructor((struct wl_proxy *) tizen_policy,
+                        TIZEN_POLICY_GET_VISIBILITY, &tizen_visibility_interface, NULL, surface);
+
+       return (struct tizen_visibility *) id;
+}
+
+static inline void
+tizen_policy_activate(struct tizen_policy *tizen_policy, struct wl_surface *surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_policy,
+                        TIZEN_POLICY_ACTIVATE, surface);
+}
+
+static inline void
+tizen_policy_position_set(struct tizen_policy *tizen_policy, struct wl_surface *surface, int32_t x, int32_t y)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_policy,
+                        TIZEN_POLICY_POSITION_SET, surface, x, y);
+}
+
+static inline void
+tizen_policy_focus_skip_set(struct tizen_policy *tizen_policy, struct wl_surface *surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_policy,
+                        TIZEN_POLICY_FOCUS_SKIP_SET, surface);
+}
+
+static inline void
+tizen_policy_focus_skip_unset(struct tizen_policy *tizen_policy, struct wl_surface *surface)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_policy,
+                        TIZEN_POLICY_FOCUS_SKIP_UNSET, surface);
+}
+
+#ifndef TIZEN_VISIBILITY_VISIBILITY_ENUM
+#define TIZEN_VISIBILITY_VISIBILITY_ENUM
+enum tizen_visibility_visibility {
+       TIZEN_VISIBILITY_VISIBILITY_UNOBSCURED = 0,
+       TIZEN_VISIBILITY_VISIBILITY_PARTIALLY_OBSCURED = 1,
+       TIZEN_VISIBILITY_VISIBILITY_FULLY_OBSCURED = 2,
+};
+#endif /* TIZEN_VISIBILITY_VISIBILITY_ENUM */
+
+struct tizen_visibility_listener {
+       /**
+        * notify - (none)
+        * @visibility: (none)
+        */
+       void (*notify)(void *data,
+                      struct tizen_visibility *tizen_visibility,
+                      uint32_t visibility);
+};
+
+static inline int
+tizen_visibility_add_listener(struct tizen_visibility *tizen_visibility,
+                             const struct tizen_visibility_listener *listener, void *data)
+{
+       return wl_proxy_add_listener((struct wl_proxy *) tizen_visibility,
+                                    (void (**)(void)) listener, data);
+}
+
+#define TIZEN_VISIBILITY_DESTROY       0
+
+static inline void
+tizen_visibility_set_user_data(struct tizen_visibility *tizen_visibility, void *user_data)
+{
+       wl_proxy_set_user_data((struct wl_proxy *) tizen_visibility, user_data);
+}
+
+static inline void *
+tizen_visibility_get_user_data(struct tizen_visibility *tizen_visibility)
+{
+       return wl_proxy_get_user_data((struct wl_proxy *) tizen_visibility);
+}
+
+static inline void
+tizen_visibility_destroy(struct tizen_visibility *tizen_visibility)
+{
+       wl_proxy_marshal((struct wl_proxy *) tizen_visibility,
+                        TIZEN_VISIBILITY_DESTROY);
+
+       wl_proxy_destroy((struct wl_proxy *) tizen_visibility);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/adaptors/wayland/virtual-keyboard-impl-wl.cpp b/adaptors/wayland/virtual-keyboard-impl-wl.cpp
new file mode 100644 (file)
index 0000000..3003364
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "virtual-keyboard-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <algorithm>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <locale-utils.h>
+#include <imf-manager-impl.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+Dali::InputMethod::ActionButton gActionButtonFunction = Dali::InputMethod::ACTION_DEFAULT;
+
+void RotateTo(int angle)
+{
+}
+
+void SetReturnKeyType( const InputMethod::ActionButton type )
+{
+}
+
+Dali::InputMethod::ActionButton GetReturnKeyType()
+{
+  return gActionButtonFunction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/wayland/window-impl-wl.cpp b/adaptors/wayland/window-impl-wl.cpp
new file mode 100644 (file)
index 0000000..cfe6cfb
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "window-impl.h"
+
+// EXTERNAL HEADERS
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/system-overlay.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <orientation.h>
+
+// INTERNAL HEADERS
+#include <window-render-surface.h>
+#include <drag-and-drop-detector-impl.h>
+#include <indicator-impl.h>
+#include <window-visibility-observer.h>
+#include <orientation-impl.h>
+
+namespace
+{
+const float INDICATOR_ANIMATION_DURATION( 0.18f ); // 180 milli seconds
+const float INDICATOR_SHOW_Y_POSITION( 0.0f );
+const float INDICATOR_HIDE_Y_POSITION( -52.0f );
+}
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_WINDOW");
+#endif
+
+/**
+ * TODO: Abstract Window class out and move this into a window implementation for Ecore
+ */
+struct Window::EventHandler
+{
+  /**
+   * Constructor
+   * @param[in]  window  A pointer to the window class.
+   */
+  EventHandler( Window* window )
+  : mWindow( window ),
+    mEcoreWindow( 0 )
+  {
+    // store ecore window handle
+    ECore::WindowRenderSurface* wlWindow( dynamic_cast< ECore::WindowRenderSurface * >( mWindow->mSurface ) );
+    if( wlWindow )
+    {
+      mEcoreWindow = wlWindow->GetWlWindow();
+    }
+    DALI_ASSERT_ALWAYS( mEcoreWindow != 0 && "There is no ecore wl window");
+  }
+
+  /**
+   * Destructor
+   */
+  ~EventHandler()
+  {
+    if ( mWindowPropertyHandler )
+    {
+      ecore_event_handler_del( mWindowPropertyHandler );
+    }
+    if ( mClientMessagehandler )
+    {
+      ecore_event_handler_del( mClientMessagehandler );
+    }
+  }
+
+  // Static methods
+
+  /// Called when the window properties are changed.
+  static Eina_Bool EcoreEventWindowPropertyChanged( void* data, int type, void* event )
+  {
+    return EINA_FALSE;
+  }
+
+  /// Called when the window properties are changed.
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+    return EINA_FALSE;
+  }
+
+  // Data
+  Window* mWindow;
+  Ecore_Event_Handler* mWindowPropertyHandler;
+  Ecore_Event_Handler* mClientMessagehandler;
+  Ecore_Wl_Window* mEcoreWindow;
+};
+
+
+Window* Window::New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Window* window = new Window();
+  window->mIsTransparent = isTransparent;
+  window->Initialize(posSize, name, className);
+  return window;
+}
+
+void Window::SetAdaptor(Dali::Adaptor& adaptor)
+{
+  DALI_ASSERT_ALWAYS( !mStarted && "Adaptor already started" );
+  mStarted = true;
+
+  // Only create one overlay per window
+  Internal::Adaptor::Adaptor& adaptorImpl = Internal::Adaptor::Adaptor::GetImplementation(adaptor);
+  Integration::Core& core = adaptorImpl.GetCore();
+  mOverlay = &core.GetSystemOverlay();
+
+  Dali::RenderTaskList taskList = mOverlay->GetOverlayRenderTasks();
+  taskList.CreateTask();
+
+  mAdaptor = &adaptorImpl;
+  mAdaptor->AddObserver( *this );
+
+  // Can only create the detector when we know the Core has been instantiated.
+  mDragAndDropDetector = DragAndDropDetector::New();
+  mAdaptor->SetDragAndDropDetector( &GetImplementation( mDragAndDropDetector ) );
+
+  if( mOrientation )
+  {
+    mOrientation->SetAdaptor(adaptor);
+  }
+
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetAdaptor(mAdaptor);
+  }
+}
+
+RenderSurface* Window::GetSurface()
+{
+  return mSurface;
+}
+
+void Window::ShowIndicator( Dali::Window::IndicatorVisibleMode visibleMode )
+{
+  DALI_LOG_TRACE_METHOD_FMT( gWindowLogFilter, "visible : %d\n", visibleMode );
+  DALI_ASSERT_DEBUG(mOverlay);
+
+  DoShowIndicator( mIndicatorOrientation );
+}
+
+void Window::RotateIndicator(Dali::Window::WindowOrientation orientation)
+{
+  DALI_LOG_TRACE_METHOD_FMT( gWindowLogFilter, "Orientation: %d\n", orientation );
+
+  DoRotateIndicator( orientation );
+}
+
+void Window::SetIndicatorBgOpacity( Dali::Window::IndicatorBgOpacity opacityMode )
+{
+  mIndicatorOpacityMode = opacityMode;
+
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetOpacityMode( opacityMode );
+  }
+}
+
+void Window::SetClass(std::string name, std::string klass)
+{
+}
+
+Window::Window()
+: mSurface(NULL),
+  mIndicatorVisible(Dali::Window::VISIBLE),
+  mIndicatorIsShown(false),
+  mShowRotatedIndicatorOnClose(false),
+  mStarted(false),
+  mIsTransparent(false),
+  mWMRotationAppSet(false),
+  mIndicator(NULL),
+  mIndicatorOrientation(Dali::Window::PORTRAIT),
+  mNextIndicatorOrientation(Dali::Window::PORTRAIT),
+  mIndicatorOpacityMode(Dali::Window::OPAQUE),
+  mOverlay(NULL),
+  mAdaptor(NULL)
+{
+}
+
+Window::~Window()
+{
+  delete mEventHandler;
+
+  if( mIndicator )
+  {
+    mIndicator->Close();
+    delete mIndicator;
+  }
+
+  if ( mAdaptor )
+  {
+    mAdaptor->RemoveObserver( *this );
+    mAdaptor->SetDragAndDropDetector( NULL );
+    mAdaptor = NULL;
+  }
+
+  delete mSurface;
+}
+
+void Window::Initialize(const PositionSize& windowPosition, const std::string& name, const std::string& className)
+{
+  // create an Wayland window by default
+  Any surface;
+  ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( windowPosition, surface, name, mIsTransparent );
+  SetClass( name, className );
+  windowSurface->Map();
+
+  mSurface = windowSurface;
+
+  mOrientation = Orientation::New(this);
+
+  // create event handler for Wayland window
+  mEventHandler = new EventHandler( this );
+}
+
+void Window::DoShowIndicator( Dali::Window::WindowOrientation lastOrientation )
+{
+  if( mIndicator == NULL )
+  {
+    if( mIndicatorVisible != Dali::Window::INVISIBLE )
+    {
+      mIndicator = new Indicator( mAdaptor, mIndicatorOrientation, this );
+      mIndicator->SetOpacityMode( mIndicatorOpacityMode );
+      Dali::Actor actor = mIndicator->GetActor();
+      SetIndicatorActorRotation();
+      mOverlay->Add(actor);
+    }
+    // else don't create a hidden indicator
+  }
+  else // Already have indicator
+  {
+    if( mIndicatorVisible == Dali::Window::VISIBLE )
+    {
+      // If we are resuming, and rotation has changed,
+      if( mIndicatorIsShown == false && mIndicatorOrientation != mNextIndicatorOrientation )
+      {
+        // then close current indicator and open new one
+        mShowRotatedIndicatorOnClose = true;
+        mIndicator->Close(); // May synchronously call IndicatorClosed() callback & 1 level of recursion
+        // Don't show actor - will contain indicator for old orientation.
+      }
+    }
+  }
+
+  // set indicator visible mode
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetVisible( mIndicatorVisible );
+  }
+
+  bool show = (mIndicatorVisible != Dali::Window::INVISIBLE );
+  SetIndicatorProperties( show, lastOrientation );
+  mIndicatorIsShown = show;
+}
+
+void Window::DoRotateIndicator( Dali::Window::WindowOrientation orientation )
+{
+  if( mIndicatorIsShown )
+  {
+    mShowRotatedIndicatorOnClose = true;
+    mNextIndicatorOrientation = orientation;
+    mIndicator->Close(); // May synchronously call IndicatorClosed() callback
+  }
+  else
+  {
+    // Save orientation for when the indicator is next shown
+    mShowRotatedIndicatorOnClose = false;
+    mNextIndicatorOrientation = orientation;
+  }
+}
+
+void Window::SetIndicatorProperties( bool isShow, Dali::Window::WindowOrientation lastOrientation )
+{
+}
+
+void Window::IndicatorTypeChanged(Indicator::Type type)
+{
+}
+
+void Window::IndicatorClosed( Indicator* indicator )
+{
+  DALI_LOG_TRACE_METHOD( gWindowLogFilter );
+
+  if( mShowRotatedIndicatorOnClose )
+  {
+    Dali::Window::WindowOrientation currentOrientation = mIndicatorOrientation;
+    mIndicator->Open(mNextIndicatorOrientation);
+    mIndicatorOrientation = mNextIndicatorOrientation;
+    SetIndicatorActorRotation();
+    DoShowIndicator(currentOrientation);
+  }
+}
+
+void Window::IndicatorVisibilityChanged(bool isVisible)
+{
+  mIndicatorVisibilityChangedSignal.Emit(isVisible);
+}
+
+void Window::SetIndicatorActorRotation()
+{
+  DALI_LOG_TRACE_METHOD( gWindowLogFilter );
+  DALI_ASSERT_DEBUG( mIndicator != NULL );
+
+  Dali::Actor actor = mIndicator->GetActor();
+  switch( mIndicatorOrientation )
+  {
+    case Dali::Window::PORTRAIT:
+      actor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(0), Vector3::ZAXIS );
+      break;
+    case Dali::Window::PORTRAIT_INVERSE:
+      actor.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(180), Vector3::ZAXIS );
+      break;
+    case Dali::Window::LANDSCAPE:
+      actor.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(270), Vector3::ZAXIS );
+      break;
+    case Dali::Window::LANDSCAPE_INVERSE:
+      actor.SetParentOrigin( ParentOrigin::CENTER_RIGHT );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(90), Vector3::ZAXIS );
+      break;
+  }
+}
+
+void Window::Raise()
+{
+}
+
+void Window::Lower()
+{
+}
+
+void Window::Activate()
+{
+}
+
+Dali::DragAndDropDetector Window::GetDragAndDropDetector() const
+{
+  return mDragAndDropDetector;
+}
+
+Dali::Any Window::GetNativeHandle() const
+{
+  if(mEventHandler)
+  {
+    return mEventHandler->mEcoreWindow;
+  }
+  else
+  {
+    return Dali::Any();
+  }
+}
+
+void Window::OnStart()
+{
+  DoShowIndicator( mIndicatorOrientation );
+}
+
+void Window::OnPause()
+{
+}
+
+void Window::OnResume()
+{
+  // resume indicator status
+  if( mIndicator != NULL )
+  {
+    // Restore own indicator opacity
+    // Send opacity mode to indicator service when app resumed
+    mIndicator->SetOpacityMode( mIndicatorOpacityMode );
+  }
+}
+
+void Window::OnStop()
+{
+  if( mIndicator )
+  {
+    mIndicator->Close();
+  }
+
+  delete mIndicator;
+  mIndicator = NULL;
+}
+
+void Window::OnDestroy()
+{
+  mAdaptor = NULL;
+}
+
+void Window::AddAvailableOrientation(Dali::Window::WindowOrientation orientation)
+{
+  bool found = false;
+
+  for( std::size_t i=0; i<mAvailableOrientations.size(); i++ )
+  {
+    if(mAvailableOrientations[i] == orientation)
+    {
+      found = true;
+      break;
+    }
+  }
+
+  if( ! found )
+  {
+    mAvailableOrientations.push_back(orientation);
+    SetAvailableOrientations( mAvailableOrientations );
+  }
+}
+
+void Window::RemoveAvailableOrientation(Dali::Window::WindowOrientation orientation)
+{
+  for( std::vector<Dali::Window::WindowOrientation>::iterator iter = mAvailableOrientations.begin();
+       iter != mAvailableOrientations.end(); ++iter )
+  {
+    if( *iter == orientation )
+    {
+      mAvailableOrientations.erase( iter );
+      break;
+    }
+  }
+  SetAvailableOrientations( mAvailableOrientations );
+}
+
+void Window::SetAvailableOrientations(const std::vector<Dali::Window::WindowOrientation>& orientations)
+{
+  DALI_ASSERT_ALWAYS( mAvailableOrientations.size() <= 4 && "Incorrect number of available orientations" );
+}
+
+const std::vector<Dali::Window::WindowOrientation>& Window::GetAvailableOrientations()
+{
+  return mAvailableOrientations;
+}
+
+void Window::SetPreferredOrientation(Dali::Window::WindowOrientation orientation)
+{
+  mPreferredOrientation = orientation;
+}
+
+Dali::Window::WindowOrientation Window::GetPreferredOrientation()
+{
+  return mPreferredOrientation;
+}
+
+void Window::RotationDone( int orientation, int width, int height )
+{
+}
+
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/wayland/window-render-surface-wl.cpp b/adaptors/wayland/window-render-surface-wl.cpp
new file mode 100644 (file)
index 0000000..38a2d44
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "window-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <ecore-wl-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+#include <base/display-connection.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gRenderSurfaceLogFilter;
+#endif
+
+namespace ECore
+{
+
+namespace
+{
+
+const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
+
+} // unnamed namespace
+
+WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize,
+                                          Any surface,
+                                          const std::string& name,
+                                          bool isTransparent)
+: EcoreWlRenderSurface( positionSize, surface, name, isTransparent ),
+  mNeedToApproveDeiconify(false)
+{
+  DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
+  Init( surface );
+}
+
+WindowRenderSurface::~WindowRenderSurface()
+{
+  if( mOwnSurface )
+  {
+    ecore_wl_window_free( mWlWindow );
+  }
+}
+
+Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
+{
+  // already an e-core type
+  return mWlWindow;
+}
+
+Any WindowRenderSurface::GetSurface()
+{
+  // already an e-core type
+  return Any( mWlWindow );
+}
+
+Ecore_Wl_Window* WindowRenderSurface::GetWlWindow()
+{
+  return mWlWindow;
+}
+
+void WindowRenderSurface::RequestToApproveDeiconify()
+{
+  mNeedToApproveDeiconify = true;
+}
+
+void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+
+  eglImpl.ChooseConfig(true, mColorDepth);
+}
+
+void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+
+  // create the EGL surface
+  ecore_wl_window_surface_create(mWlWindow);
+  mEglWindow = wl_egl_window_create(ecore_wl_window_surface_get(mWlWindow), mPosition.width, mPosition.height);
+  eglImpl.CreateSurfaceWindow( (EGLNativeWindowType)mEglWindow, mColorDepth ); // reinterpret_cast does not compile
+}
+
+void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+  eglImpl.DestroySurface();
+  wl_egl_window_destroy(mEglWindow);
+  mEglWindow = NULL;
+}
+
+bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  wl_egl_window_destroy(mEglWindow);
+  mEglWindow = wl_egl_window_create(ecore_wl_window_surface_get(mWlWindow), mPosition.width, mPosition.height);
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+  return eglImpl.ReplaceSurfaceWindow( (EGLNativeWindowType)mEglWindow ); // reinterpret_cast does not compile
+}
+
+void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
+{
+  bool needToMove = false;
+  bool needToResize = false;
+
+  // check moving
+  if( (fabs(positionSize.x - mPosition.x) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.y - mPosition.y) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToMove = true;
+  }
+
+  // check resizing
+  if( (fabs(positionSize.width - mPosition.width) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.height - mPosition.height) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToResize = true;
+  }
+
+  if(needToMove)
+  {
+    ecore_wl_window_move(mWlWindow, positionSize.x, positionSize.y);
+    mPosition = positionSize;
+  }
+  if (needToResize)
+  {
+    ecore_wl_window_resize(mWlWindow, positionSize.width, positionSize.height, 0);
+    mPosition = positionSize;
+  }
+
+}
+
+void WindowRenderSurface::Map()
+{
+  ecore_wl_window_show(mWlWindow);
+}
+
+void WindowRenderSurface::StartRender()
+{
+}
+
+bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
+{
+  // nothing to do for windows
+  return true;
+}
+
+void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
+{
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+  eglImpl.SwapBuffers();
+
+  // When the window is deiconified, it approves the deiconify operation to window manager after rendering
+  if(mNeedToApproveDeiconify)
+  {
+    // SwapBuffer is desychronized. So make sure to sychronize when window is deiconified.
+    glAbstraction.Finish();
+
+    //FIXME
+
+    mNeedToApproveDeiconify = false;
+  }
+}
+
+void WindowRenderSurface::StopRender()
+{
+}
+
+void WindowRenderSurface::SetViewMode( ViewMode viewMode )
+{
+  //FIXME
+}
+
+void WindowRenderSurface::CreateWlRenderable()
+{
+   // if width or height are zero, go full screen.
+  if ( (mPosition.width == 0) || (mPosition.height == 0) )
+  {
+    // Default window size == screen size
+    mPosition.x = 0;
+    mPosition.y = 0;
+
+    ecore_wl_screen_size_get( &mPosition.width, &mPosition.height );
+  }
+
+  mWlWindow = ecore_wl_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
+
+  if ( mWlWindow == 0 )
+  {
+      DALI_ASSERT_ALWAYS(0 && "Failed to create X window");
+  }
+
+  //FIXME
+}
+
+void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
+{
+  mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
+}
+
+void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ )
+{
+  // Nothing to do.
+}
+
+void WindowRenderSurface::ReleaseLock()
+{
+  // Nothing to do.
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/wayland/window-render-surface.h b/adaptors/wayland/window-render-surface.h
new file mode 100644 (file)
index 0000000..7aea88b
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef __DALI_INTERNAL_ECORE_WL_WINDOW_RENDER_SURFACE_H__
+#define __DALI_INTERNAL_ECORE_WL_WINDOW_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <ecore-wl-render-surface.h>
+#include <wayland-egl.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+/**
+ * @copydoc Dali::ECore::EcoreWlRenderSurface.
+ * Window specialization.
+ */
+class WindowRenderSurface : public EcoreWlRenderSurface
+{
+public:
+
+  /**
+    * Uses an Wayland surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a Wayland-window or Wayland-pixmap (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  WindowRenderSurface( Dali::PositionSize positionSize,
+                       Any surface,
+                       const std::string& name,
+                       bool isTransparent = false );
+
+  /**
+   * @copydoc Dali::ECore::EcoreWlRenderSurface::~EcoreWlRenderSurface
+   */
+  virtual ~WindowRenderSurface();
+
+public: // API
+
+  /**
+   * @copydoc Dali::RenderSurface::GetDrawable()
+   */
+  virtual Ecore_Wl_Window* GetDrawable();
+
+  /**
+   * Request to approve deiconify operation
+   * If it is requested, it will send ECORE_X_ATOM_E_DEICONIFY_APPROVE event to window manager after rendering
+   */
+  void RequestToApproveDeiconify();
+
+  /**
+   * Map window
+   */
+  virtual void Map();
+
+  /**
+   * @copydoc Dali::ECore::EcoreWlRenderSurface::GetSurface()
+   */
+  virtual Any GetSurface();
+
+  /**
+   * @copydoc Dali::ECore::EcoreWlRenderSurface::GetWlWindow()
+   */
+  virtual Ecore_Wl_Window* GetWlWindow();
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize);
+
+  /**
+   * @copydoc Dali::RenderSurface::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction );
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurface::StopRender()
+   */
+  virtual void StopRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReleaseLock()
+   */
+  virtual void ReleaseLock();
+
+protected:
+
+  /**
+   * Create WlWindow
+   */
+  virtual void CreateWlRenderable();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::ECore::EcoreWlRenderSurface::UseExistingRenderable
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId );
+
+private: // Data
+
+  Ecore_Wl_Window*   mWlWindow; ///< Wayland-Window
+  wl_egl_window*     mEglWindow;
+  bool             mNeedToApproveDeiconify; ///< Whether need to send ECORE_X_ATOM_E_DEICONIFY_APPROVE event
+
+}; // class WindowRenderSurface
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ECORE_X_WINDOW_RENDER_SURFACE_H__
diff --git a/adaptors/x11/accessibility-adaptor-impl-x.cpp b/adaptors/x11/accessibility-adaptor-impl-x.cpp
new file mode 100644 (file)
index 0000000..c7f90f5
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "accessibility-adaptor-impl.h"
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+#include <Ecore_X.h>
+#include <Elementary.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/gesture-requests.h>
+
+// INTERNAL INCLUDES
+#include "system-settings.h"
+
+#define MSG_DOMAIN_CONTROL_ACCESS (int)ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace {
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+} // unnamed namespace
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_ACTIVATE;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  Dali::AccessibilityAdaptor handle( this );
+
+  bool indicatorFocused = false;
+
+  // Check whether the Indicator is focused
+  if( mIndicator && mIndicator->IsConnected() )
+  {
+    // Check the position and size of Indicator actor
+    Dali::Actor indicatorActor = mIndicator->GetActor();
+    Vector3 position = Vector3(0.0f, 0.0f, 0.0f);
+    Vector3 size = indicatorActor.GetCurrentSize();
+
+    if(mReadPosition.x >= position.x &&
+       mReadPosition.x <= position.x + size.width &&
+       mReadPosition.y >= position.y &&
+       mReadPosition.y <= position.y + size.height)
+    {
+      indicatorFocused = true;
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Indicator area!!!!\n", __FUNCTION__, __LINE__);
+    }
+  }
+
+  if( mIndicator )
+  {
+    if( !mIndicatorFocused && indicatorFocused )
+    {
+      // If Indicator is focused, the focus should be cleared in Dali focus chain.
+      if( mActionHandler )
+      {
+        mActionHandler->ClearAccessibilityFocus();
+      }
+    }
+    else if( mIndicatorFocused && !indicatorFocused )
+    {
+      Elm_Access_Action_Info actionInfo;
+      actionInfo.action_type = ELM_ACCESS_ACTION_UNHIGHLIGHT;
+
+      // Indicator should be unhighlighted
+      ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Send unhighlight message to indicator!!!!\n", __FUNCTION__, __LINE__);
+    }
+
+    mIndicatorFocused = indicatorFocused;
+
+    // Send accessibility READ action information to Indicator
+    if( mIndicatorFocused )
+    {
+      Elm_Access_Action_Info actionInfo;
+      actionInfo.x = mReadPosition.x;
+      actionInfo.y = mReadPosition.y;
+
+      if(allowReadAgain)
+      {
+        actionInfo.action_type = ELM_ACCESS_ACTION_READ;
+      }
+      else
+      {
+        actionInfo.action_type = static_cast<Elm_Access_Action_Type>( GetElmAccessActionOver() );
+      }
+
+      ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+
+      DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] Send READ message to indicator!!!!\n", __FUNCTION__, __LINE__);
+    }
+  }
+
+  if( mActionHandler && !mIndicatorFocused)
+  {
+    // If Indicator is not focused, the accessibility actions should be handled by the registered
+    // accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead(allowReadAgain);
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_UP;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    Elm_Access_Action_Info actionInfo;
+    actionInfo.action_type = ELM_ACCESS_ACTION_DOWN;
+
+    ret = mIndicator->SendMessage(MSG_DOMAIN_CONTROL_ACCESS, actionInfo.action_type, &actionInfo, sizeof(actionInfo));
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageLeft();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageRight();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToFirst();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToLast();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromTop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromNext();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionZoom();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadIndicatorInformationEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadIndicatorInformation();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPauseResume();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  bool ret = false;
+
+  if( mIndicator && mIndicatorFocused )
+  {
+    // TODO: Send message to indicator with the correct action type
+  }
+  else if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionStartStop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/clipboard-impl-x.cpp b/adaptors/x11/clipboard-impl-x.cpp
new file mode 100644 (file)
index 0000000..eafd12a
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "clipboard-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore_X.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor-impl.h>
+#include <ecore-x-window-interface.h>
+#include <singleton-service-impl.h>
+
+namespace //unnamed namespace
+{
+const char* const CBHM_WINDOW = "CBHM_XWIN";
+const char* const CBHM_MSG = "CBHM_MSG";
+const char* const CBHM_ITEM = "CBHM_ITEM";
+const char* const CBHM_cCOUNT = "CBHM_cCOUNT";
+const char* const CBHM_ERROR = "CBHM_ERROR";
+const char* const SET_ITEM = "SET_ITEM";
+const char* const SHOW = "show0";
+const char* const HIDE = "cbhm_hide";
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+BaseHandle Create()
+{
+  BaseHandle handle( Clipboard::Get() );
+
+  if ( !handle && Adaptor::IsAvailable() )
+  {
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
+      Any nativewindow = adaptorImpl.GetNativeWindowHandle();
+
+      // The Ecore_X_Window needs to use the Clipboard.
+      // Only when the render surface is window, we can get the Ecore_X_Window.
+      Ecore_X_Window ecoreXwin( AnyCast<Ecore_X_Window>(nativewindow) );
+      if (ecoreXwin)
+      {
+        // If we fail to get Ecore_X_Window, we can't use the Clipboard correctly.
+        // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
+        // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
+        Dali::Clipboard clipboard = Dali::Clipboard( new Clipboard( ecoreXwin ) );
+        service.Register( typeid( clipboard ), clipboard );
+        handle = clipboard;
+      }
+      else
+      {
+        DALI_LOG_ERROR("Failed to get native window handle");
+      }
+    }
+  }
+
+  return handle;
+}
+TypeRegistration CLIPBOARD_TYPE( typeid(Dali::Clipboard), typeid(Dali::BaseHandle), Create, true /* Create Instance At Startup */ );
+
+} // unnamed namespace
+
+Clipboard::Clipboard( Ecore_X_Window ecoreXwin)
+{
+  mApplicationWindow = ecoreXwin;
+}
+
+Clipboard::~Clipboard()
+{
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  Dali::Clipboard clipboard;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Clipboard ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      clipboard = Dali::Clipboard( dynamic_cast< Clipboard* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return clipboard;
+}
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+  Ecore_X_Atom atomCbhmItem = ecore_x_atom_get( CBHM_ITEM );
+  Ecore_X_Atom dataType = ECORE_X_ATOM_STRING;
+
+  // Set item (property) to send
+  ecore_x_window_prop_property_set( cbhmWin, atomCbhmItem, dataType, 8, const_cast<char*>( itemData.c_str() ), itemData.length() + 1 );
+  ecore_x_sync();
+
+  // Trigger sending of item (property)
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent(ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SET_ITEM );
+  return true;
+}
+
+/*
+ * Get string at given index of clipboard
+ */
+std::string Clipboard::GetItem( unsigned int index )  // change string to a Dali::Text object.
+{
+  if ( index >= NumberOfItems() )
+  {
+    return "";
+  }
+
+  std::string emptyString( "" );
+  char sendBuf[20];
+
+  snprintf( sendBuf, 20,  "%s%d", CBHM_ITEM, index );
+  Ecore_X_Atom xAtomCbhmItem = ecore_x_atom_get( sendBuf );
+  Ecore_X_Atom xAtomItemType = 0;
+
+  std::string clipboardString( ECore::WindowInterface::GetWindowProperty(xAtomCbhmItem, &xAtomItemType, index ) );
+  if ( !clipboardString.empty() )
+  {
+    Ecore_X_Atom xAtomCbhmError = ecore_x_atom_get( CBHM_ERROR );
+    if ( xAtomItemType != xAtomCbhmError )
+    {
+      return clipboardString;
+    }
+   }
+   return emptyString;
+}
+
+/*
+ * Get number of items in clipboard
+ */
+unsigned int Clipboard::NumberOfItems()
+{
+  Ecore_X_Atom xAtomCbhmCountGet = ecore_x_atom_get( CBHM_cCOUNT );
+
+  std::string ret( ECore::WindowInterface::GetWindowProperty( xAtomCbhmCountGet, NULL, 0 ) );
+  int count = 0;
+
+  if ( !ret.empty() )
+  {
+    count = atoi( ret.c_str() );
+  }
+
+  return count;
+}
+
+/**
+ * Show clipboard window
+ * Function to send message to show the Clipboard (cbhm) as no direct API available
+ * Reference elementary/src/modules/ctxpopup_copypasteUI/cbhm_helper.c
+ */
+void Clipboard::ShowClipboard()
+{
+  // Claim the ownership of the SECONDARY selection.
+  ecore_x_selection_secondary_set(mApplicationWindow, "", 1);
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+
+  // Launch the clipboard window
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent( ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SHOW );
+}
+
+void Clipboard::HideClipboard()
+{
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+  // Launch the clipboard window
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent( ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, HIDE );
+
+  // release the ownership of SECONDARY selection
+  ecore_x_selection_secondary_clear();
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/clipboard-impl.h b/adaptors/x11/clipboard-impl.h
new file mode 100644 (file)
index 0000000..22891a2
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef __DALI_INTERNAL_CLIPBOARD_H__
+#define __DALI_INTERNAL_CLIPBOARD_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+#include <Ecore_X.h>
+
+// INTERNAL INCLUDES
+#include <clipboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Clip Board
+ */
+
+class Clipboard :  public Dali::BaseObject
+{
+public:
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::Clipboard Get();
+
+  /**
+   * Constructor
+   * @param[in] ecoreXwin, The window is created by application.
+   */
+  Clipboard(Ecore_X_Window ecoreXwin);
+
+  virtual ~Clipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::SetItem()
+   */
+  bool SetItem(const std::string &itemData);
+
+  /**
+   * @copydoc Dali::Clipboard::GetItem()
+   */
+  std::string GetItem( unsigned int index );
+
+  /**
+   * @copydoc Dali::Clipboard::NumberOfClipboardItems()
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @copydoc Dali::Clipboard::ShowClipboard()
+   */
+  void ShowClipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::HideClipboard()
+   */
+  void HideClipboard();
+
+  
+private:
+  Ecore_X_Window mApplicationWindow;
+  Clipboard( const Clipboard& );
+  Clipboard& operator=( Clipboard& );
+
+}; // class clipboard
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+  inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard)
+  {
+    DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+    BaseObject& handle = clipboard.GetBaseObject();
+    return static_cast<Internal::Adaptor::Clipboard&>(handle);
+  }
+
+  inline static const  Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard)
+  {
+    DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+    const BaseObject& handle = clipboard.GetBaseObject();
+    return static_cast<const Internal::Adaptor::Clipboard&>(handle);
+  }
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_CLIPBOARD_H__
diff --git a/adaptors/x11/display-connection-impl-x.cpp b/adaptors/x11/display-connection-impl-x.cpp
new file mode 100644 (file)
index 0000000..02deebb
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "display-connection-impl.h"
+
+// EXTERNAL_HEADERS
+#include <Ecore_X.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <pixmap-render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+DisplayConnection* DisplayConnection::New()
+{
+  DisplayConnection* pDisplayConnection(new DisplayConnection());
+
+  return pDisplayConnection;
+}
+
+DisplayConnection::DisplayConnection()
+: mDisplay(NULL)
+{
+  // Because of DDK issue, we need to use separated x display instead of ecore default display
+  mDisplay = XOpenDisplay(0);
+}
+
+DisplayConnection::~DisplayConnection()
+{
+  if(mDisplay)
+  {
+    XCloseDisplay(mDisplay);
+  }
+}
+
+Any DisplayConnection::GetDisplay()
+{
+  return Any(mDisplay);
+}
+
+void DisplayConnection::ConsumeEvents()
+{
+  // check events so that we can flush the queue and avoid any potential memory leaks in X
+  // looping if events remain
+  int events(0);
+  do
+  {
+    // Check if there are any events in the queue
+    events = XEventsQueued(mDisplay, QueuedAfterFlush);
+
+    if (events > 0)
+    {
+      // Just flush event to prevent memory leak from event queue as the events get built up in
+      // memory but are only deleted when we retrieve them
+      XEvent ev;
+      XNextEvent(mDisplay, &ev);
+    }
+  }
+  while (events > 0);
+}
+
+bool DisplayConnection::InitializeEgl(EglInterface& egl)
+{
+  EglImplementation& eglImpl = static_cast<EglImplementation&>(egl);
+
+  if (!eglImpl.InitializeGles(reinterpret_cast<EGLNativeDisplayType>(mDisplay)))
+  {
+    DALI_LOG_ERROR("Failed to initialize GLES.");
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayConnection::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
+{
+  // calculate DPI
+  float xres, yres;
+
+  // 1 inch = 25.4 millimeters
+  xres = ecore_x_dpi_get();
+  yres = ecore_x_dpi_get();
+
+  dpiHorizontal = int(xres + 0.5f);  // rounding
+  dpiVertical   = int(yres + 0.5f);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/display-connection-impl.h b/adaptors/x11/display-connection-impl.h
new file mode 100644 (file)
index 0000000..c5b7a70
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
+#define __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_X.h>
+#include <ecore-x-types.h>
+
+// INTERNAL INCLUDES
+#include <base/display-connection.h>
+#include <dali/public-api/object/base-object.h>
+#include <gl/egl-implementation.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+class DisplayConnection;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnection : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnection();
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  Any GetDisplay();
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDpi
+   */
+  static void GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical);
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  void ConsumeEvents();
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeEgl
+   */
+  bool InitializeEgl(EglInterface& egl);
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~DisplayConnection();
+
+protected:
+
+  // Undefined
+  DisplayConnection(const DisplayConnection&);
+
+  // Undefined
+  DisplayConnection& operator=(const DisplayConnection& rhs);
+
+private:
+  XDisplay*   mDisplay;        ///< X-display for rendering
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ECORE_X_DIPLAY_CONNECTION_H__
diff --git a/adaptors/x11/ecore-x-event-handler.cpp b/adaptors/x11/ecore-x-event-handler.cpp
new file mode 100644 (file)
index 0000000..2e1d4ec
--- /dev/null
@@ -0,0 +1,1886 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <events/event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_Input.h>
+#include <Ecore_X.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+
+#include <cstring>
+
+#include <sys/time.h>
+
+#ifndef DALI_PROFILE_UBUNTU
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif // DALI_PROFILE_UBUNTU
+
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif // DALI_ELDBUS_AVAILABLE
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <events/gesture-manager.h>
+#include <window-render-surface.h>
+#include <clipboard-impl.h>
+#include <key-impl.h>
+#include <physical-keyboard-impl.h>
+#include <style-monitor-impl.h>
+#include <base/core-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
+Integration::Log::Filter* gClientMessageLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_CLIENT_MESSAGE");
+Integration::Log::Filter* gDragAndDropLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DND");
+Integration::Log::Filter* gImfLogging  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_IMF");
+Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_SELECTION");
+} // unnamed namespace
+#endif
+
+
+namespace
+{
+
+const char * DETENT_DEVICE_NAME = "tizen_detent";
+
+// DBUS accessibility
+#define A11Y_BUS "org.a11y.Bus"
+#define A11Y_INTERFACE "org.a11y.Bus"
+#define A11Y_PATH "/org/a11y/bus"
+#define A11Y_GET_ADDRESS "GetAddress"
+#define BUS "com.samsung.EModule"
+#define INTERFACE "com.samsung.GestureNavigation"
+#define PATH "/com/samsung/GestureNavigation"
+#define SIGNAL "GestureDetected"
+
+#ifndef DALI_PROFILE_UBUNTU
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME = "db/setting/accessibility/font_name"; // It will be update at vconf-key.h and replaced.
+#endif // DALI_PROFILE_UBUNTU
+
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+#ifndef DALI_PROFILE_UBUNTU
+const char * CLIPBOARD_ATOM                = "CBHM_MSG";
+const char * CLIPBOARD_SET_OWNER_MESSAGE   = "SET_OWNER";
+#endif // DALI_PROFILE_UBUNTU
+
+/// The atoms required by Ecore for Drag & Drop behaviour.
+Ecore_X_Atom DRAG_AND_DROP_ATOMS[] =
+{
+  ECORE_X_ATOM_XDND_ACTION_COPY,
+};
+
+/// The types that we support.
+const char * DRAG_AND_DROP_TYPES[] =
+{
+  ECORE_X_SELECTION_TARGET_UTF8_STRING,
+};
+
+const unsigned int DRAG_AND_DROP_ATOMS_NUMBER = sizeof( DRAG_AND_DROP_ATOMS ) / sizeof( Ecore_X_Atom );
+const unsigned int DRAG_AND_DROP_TYPES_NUMBER = sizeof( DRAG_AND_DROP_TYPES ) / sizeof( const char * );
+
+const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3;
+
+#ifdef DALI_ELDBUS_AVAILABLE
+// DBus gesture string matching lists.
+// TODO: This needs moving to its own module.
+const char * ElDBusAccessibilityFingerCountStrings[] =
+{
+  "OneFinger",
+  "TwoFingers",
+  "ThreeFingers"
+};
+const unsigned int FingerCountStringsTotal = sizeof( ElDBusAccessibilityFingerCountStrings ) / sizeof( ElDBusAccessibilityFingerCountStrings[0] );
+enum GestureType
+{
+  GESTURE_TYPE_NONE,
+  GESTURE_TYPE_HOVER,
+  GESTURE_TYPE_SINGLE_TAP,
+  GESTURE_TYPE_DOUBLE_TAP,
+  GESTURE_TYPE_TRIPLE_TAP
+};
+struct GestureTypeTable
+{
+  const char* name;
+  const GestureType type;
+};
+GestureTypeTable ElDBusAccessibilityFullEventTypeStrings[] =
+{
+  { "Hover",     GESTURE_TYPE_HOVER      },
+  { "SingleTap", GESTURE_TYPE_SINGLE_TAP },
+  { "DoubleTap", GESTURE_TYPE_DOUBLE_TAP },
+  { "TripleTap", GESTURE_TYPE_TRIPLE_TAP }
+};
+const unsigned int FullEventTypeStringsTotal = sizeof( ElDBusAccessibilityFullEventTypeStrings ) / sizeof( ElDBusAccessibilityFullEventTypeStrings[0] );
+enum SubGestureType
+{
+  SUB_GESTURE_TYPE_NONE,
+  SUB_GESTURE_TYPE_FLICK
+};
+struct SubGestureTypeTable
+{
+  const char* name;
+  const SubGestureType type;
+};
+SubGestureTypeTable ElDBusAccessibilityDirectionalEventTypeStrings[] =
+{
+  { "Flick", SUB_GESTURE_TYPE_FLICK }
+};
+const unsigned int DirectionalEventTypeStringsTotal = sizeof( ElDBusAccessibilityDirectionalEventTypeStrings ) / sizeof( ElDBusAccessibilityDirectionalEventTypeStrings[0] );
+enum GestureDirection
+{
+  GESTURE_DIRECTION_NONE,
+  GESTURE_DIRECTION_UP,
+  GESTURE_DIRECTION_DOWN,
+  GESTURE_DIRECTION_LEFT,
+  GESTURE_DIRECTION_RIGHT,
+  GESTURE_DIRECTION_UP_RETURN,
+  GESTURE_DIRECTION_DOWN_RETURN,
+  GESTURE_DIRECTION_LEFT_RETURN,
+  GESTURE_DIRECTION_RIGHT_RETURN
+};
+struct GestureDirectionTable
+{
+       const char* name;
+       const GestureDirection direction;
+};
+GestureDirectionTable ElDBusAccessibilityDirectionStrings[] =
+{
+  { "Up",           GESTURE_DIRECTION_UP           },
+  { "Down",         GESTURE_DIRECTION_DOWN         },
+  { "Left",         GESTURE_DIRECTION_LEFT         },
+  { "Right",        GESTURE_DIRECTION_RIGHT        },
+  { "UpReturn",     GESTURE_DIRECTION_UP_RETURN    },
+  { "DownReturn",   GESTURE_DIRECTION_DOWN_RETURN  },
+  { "LeftReturn",   GESTURE_DIRECTION_LEFT_RETURN  },
+  { "RightReturn",  GESTURE_DIRECTION_RIGHT_RETURN }
+};
+const unsigned int DirectionStringsTotal = sizeof( ElDBusAccessibilityDirectionStrings ) / sizeof( ElDBusAccessibilityDirectionStrings[0] );
+#endif // DALI_ELDBUS_AVAILABLE
+
+/**
+ * Ecore_Event_Modifier enums in Ecore_Input.h do not match Ecore_IMF_Keyboard_Modifiers in Ecore_IMF.h.
+ * This function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Modifiers enums.
+ * @param[in] ecoreModifier the Ecore_Event_Modifier input.
+ * @return the Ecore_IMF_Keyboard_Modifiers output.
+ */
+Ecore_IMF_Keyboard_Modifiers EcoreInputModifierToEcoreIMFModifier(unsigned int ecoreModifier)
+{
+   int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
+
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
+   }
+
+   if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
+   {
+     modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
+   }
+
+   return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
+}
+
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+} // unnamed namespace
+
+// Impl to hide EFL implementation.
+struct EventHandler::Impl
+{
+  // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  Impl( EventHandler* handler, Ecore_X_Window window )
+  : mHandler( handler ),
+    mEcoreEventHandler(),
+    mWindow( window ),
+    mXiDeviceId( 0 )
+#ifdef DALI_ELDBUS_AVAILABLE
+  , mSessionConnection( NULL ),
+    mA11yConnection( NULL )
+#endif
+  {
+    // Only register for touch and key events if we have a window
+    if ( window != 0 )
+    {
+      // Register Touch events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_DOWN,   EcoreEventMouseButtonDown,   handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_UP,     EcoreEventMouseButtonUp,     handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_MOVE,          EcoreEventMouseButtonMove,   handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_OUT,           EcoreEventMouseButtonUp,     handler ) ); // process mouse out event like up event
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_CANCEL, EcoreEventMouseButtonCancel, handler ) );
+
+      // Register Mouse wheel events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_MOUSE_WHEEL,        EcoreEventMouseWheel,      handler ) );
+
+      // Register Key events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,           EcoreEventKeyDown,         handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_EVENT_KEY_UP,             EcoreEventKeyUp,           handler ) );
+
+      // Register Focus events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_FOCUS_IN,  EcoreEventWindowFocusIn,   handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_FOCUS_OUT, EcoreEventWindowFocusOut,  handler ) );
+
+      // Register Window damage events
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_DAMAGE,    EcoreEventWindowDamaged, handler ) );
+
+      // Enable Drag & Drop and register DnD events
+      ecore_x_dnd_aware_set( window, EINA_TRUE );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_ENTER,       EcoreEventDndEnter,            handler) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_POSITION,    EcoreEventDndPosition,         handler) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_LEAVE,       EcoreEventDndLeave,            handler) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_DROP,        EcoreEventDndDrop,             handler) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_FINISHED,    EcoreEventDndFinished,         handler) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_XDND_STATUS,      EcoreEventDndStatus,           handler) );
+
+      // Register Client message events - accessibility etc.
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, handler ) );
+
+      // Register Selection event - clipboard selection, Drag & Drop selection etc.
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_SELECTION_CLEAR, EcoreEventSelectionClear, handler ) );
+      mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_SELECTION_NOTIFY, EcoreEventSelectionNotify, handler ) );
+
+      // Initialize Xi2 system
+      Display* display = static_cast< Display* >(ecore_x_display_get());
+      Ecore_X_Window rootWindow = ecore_x_window_root_first_get();
+      int opcode = 0, event = 0, error = 0;
+      int major = XI_2_Major;
+      int minor = XI_2_Minor;
+      int deviceCount = 0;
+      XIEventMask xiEventMask;
+
+      // Check if X input extension available
+      if( XQueryExtension( display, "XInputExtension", &opcode, &event, &error ) )
+      {
+        // We support version 2.0
+        if( XIQueryVersion( display, &major, &minor ) != BadRequest )
+        {
+          xiEventMask.deviceid = XIAllDevices;
+
+          // Check device id
+          bool match = false;
+          XIDeviceInfo* deviceInfo = NULL;
+          deviceInfo = XIQueryDevice( display, XIAllDevices, &deviceCount );
+
+          for( int i = 0; i < deviceCount; i++ )
+          {
+            if( !strncmp( deviceInfo[i].name, DETENT_DEVICE_NAME, strlen( DETENT_DEVICE_NAME ) ) )
+            {
+              xiEventMask.deviceid = deviceInfo[i].deviceid;
+              match = true;
+              break;
+            }
+          }
+
+          if( match )
+          {
+            mXiDeviceId = xiEventMask.deviceid;
+
+            // SelectXi2Event
+            Dali::Vector< unsigned char > mask;
+            std::size_t xiMaskLen = XIMaskLen( XI_LASTEVENT );
+            mask.Reserve( xiMaskLen );
+            xiEventMask.mask = mask.Begin();
+
+            XISetMask( xiEventMask.mask, XI_RawMotion );
+
+            xiEventMask.mask_len = xiMaskLen * sizeof( unsigned char );
+
+            int ret = XISelectEvents( display, rootWindow, &xiEventMask, 1 );
+            if( ret == 0 )
+            {
+              // Register custom wheel events
+              mEcoreEventHandler.push_back( ecore_event_handler_add( ECORE_X_EVENT_GENERIC, EcoreEventCustomWheel, handler ) );
+            }
+            else
+            {
+              DALI_LOG_INFO( gImfLogging, Debug::General, "Failed to Select Events\n" );
+            }
+          }
+
+          if( deviceInfo != NULL )
+          {
+            XIFreeDeviceInfo( deviceInfo );
+          }
+        }
+        else
+        {
+          DALI_LOG_INFO( gImfLogging, Debug::General, "Failed to query XI Version\n" );
+        }
+      }
+      else
+      {
+        DALI_LOG_INFO( gImfLogging, Debug::General, "Failed to query XInputExtension\n" );
+      }
+
+#ifndef DALI_PROFILE_UBUNTU
+      // Register Vconf notify - font name, font size and style
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, handler );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, handler );
+#endif // DALI_PROFILE_UBUNTU
+
+#ifdef DALI_ELDBUS_AVAILABLE
+
+      // Initialize ElDBus.
+      DALI_LOG_INFO( gImfLogging, Debug::General, "Starting DBus Initialization" );
+      eldbus_init();
+
+      mSessionConnection = eldbus_connection_get( ELDBUS_CONNECTION_TYPE_SESSION );
+
+      Eldbus_Object *a11yObject = eldbus_object_get( mSessionConnection, A11Y_BUS, A11Y_PATH );
+      Eldbus_Proxy *elDBusManager = eldbus_proxy_get( a11yObject, A11Y_INTERFACE );
+
+      // Pass in handler in the cb_data field so we can access the accessibility adaptor within the callback.
+      eldbus_proxy_call( elDBusManager, A11Y_GET_ADDRESS, EcoreElDBusInitialisation, handler, -1, "" );
+
+      DALI_LOG_INFO( gImfLogging, Debug::General, "Finished DBus Initialization" );
+
+#endif // DALI_ELDBUS_AVAILABLE
+    }
+  }
+
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged );
+    vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged );
+#endif // DALI_PROFILE_UBUNTU
+
+    for( std::vector<Ecore_Event_Handler*>::iterator iter = mEcoreEventHandler.begin(), endIter = mEcoreEventHandler.end(); iter != endIter; ++iter )
+    {
+      ecore_event_handler_del( *iter );
+    }
+
+#ifdef DALI_ELDBUS_AVAILABLE
+
+    // Close down ElDBus
+    if( mA11yConnection )
+    {
+      eldbus_connection_unref( mA11yConnection );
+    }
+
+    if( mSessionConnection )
+    {
+      eldbus_connection_unref( mSessionConnection );
+    }
+
+    eldbus_shutdown();
+
+#endif // DALI_ELDBUS_AVAILABLE
+  }
+
+  // Static methods
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Touch Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a touch down is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonDown( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Button *touchEvent( (Ecore_Event_Mouse_Button*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == handler->mImpl->mWindow )
+    {
+      TouchPoint::State state ( TouchPoint::Down );
+
+      // Check if the buttons field is set and ensure it's the primary touch button.
+      // If this event was triggered by buttons other than the primary button (used for touch), then
+      // just send an interrupted event to Core.
+      if ( touchEvent->buttons && (touchEvent->buttons != PRIMARY_TOUCH_BUTTON_ID ) )
+      {
+        state = TouchPoint::Interrupted;
+      }
+
+      TouchPoint point( touchEvent->multi.device, state, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch up is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonUp( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Button *touchEvent( (Ecore_Event_Mouse_Button*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == handler->mImpl->mWindow )
+    {
+      TouchPoint point( touchEvent->multi.device, TouchPoint::Up, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch motion is received.
+   */
+  static Eina_Bool EcoreEventMouseButtonMove( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Move *touchEvent( (Ecore_Event_Mouse_Move*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( touchEvent->window == handler->mImpl->mWindow )
+    {
+      TouchPoint point( touchEvent->multi.device, TouchPoint::Motion, touchEvent->x, touchEvent->y );
+      handler->SendEvent( point, touchEvent->timestamp );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a touch is canceled.
+   */
+  static Eina_Bool EcoreEventMouseButtonCancel( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Button *touchEvent( (Ecore_Event_Mouse_Button*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if( touchEvent->window == handler->mImpl->mWindow )
+    {
+      TouchPoint point( touchEvent->multi.device, TouchPoint::Interrupted, 0.0f, 0.0f );
+      handler->SendEvent( point, touchEvent->timestamp );
+
+      DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT EcoreEventMouseButtonCancel\n" );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Wheel Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a mouse wheel is received.
+   */
+  static Eina_Bool EcoreEventMouseWheel( void* data, int type, void* event )
+  {
+    Ecore_Event_Mouse_Wheel *mouseWheelEvent( (Ecore_Event_Mouse_Wheel*)event );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT Ecore_Event_Mouse_Wheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent->direction, mouseWheelEvent->modifiers, mouseWheelEvent->x, mouseWheelEvent->y, mouseWheelEvent->z );
+
+    EventHandler* handler( (EventHandler*)data );
+    if ( mouseWheelEvent->window == handler->mImpl->mWindow )
+    {
+      WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent->direction, mouseWheelEvent->modifiers, Vector2(mouseWheelEvent->x, mouseWheelEvent->y), mouseWheelEvent->z, mouseWheelEvent->timestamp );
+      handler->SendWheelEvent( wheelEvent );
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a custom wheel is received.
+   */
+  static Eina_Bool EcoreEventCustomWheel( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Generic *genericEvent( (Ecore_X_Event_Generic*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    switch( genericEvent->evtype )
+    {
+      case XI_RawMotion:
+      {
+        XIRawEvent* xiRawEvent = static_cast< XIRawEvent* >( genericEvent->data );
+        unsigned int timeStamp = 0;
+
+        if( xiRawEvent->deviceid != handler->mImpl->mXiDeviceId )
+        {
+          return ECORE_CALLBACK_PASS_ON;
+        }
+
+        // X(0): rotate: NOT USED
+        // Y(1): timestamp
+        // Z(2): direction
+
+        double* value = xiRawEvent->raw_values;
+
+        if( XIMaskIsSet( xiRawEvent->valuators.mask, 1) )
+        {
+          timeStamp = static_cast< unsigned int >( *(value + 1) );
+        }
+
+        if( XIMaskIsSet( xiRawEvent->valuators.mask, 2) )
+        {
+          // if z == 1, clockwise
+          // otherwise counter-clockwise
+          int z = static_cast< int >( *(value + 2) );
+
+          // In DALi, positive value means clockwise, and negative value means counter-clockwise
+          if( z == 0 )
+          {
+            z = -1;
+          }
+
+          DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT EcoreEventCustomWheel: z: %d\n", z );
+
+          WheelEvent wheelEvent( WheelEvent::CUSTOM_WHEEL, 0, 0, Vector2(0.0f, 0.0f), z, timeStamp );
+          handler->SendWheelEvent( wheelEvent );
+        }
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Key Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a key down is received.
+   */
+  static Eina_Bool EcoreEventKeyDown( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventKeyDown \n" );
+
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Event_Key *keyEvent( (Ecore_Event_Key*)event );
+    bool eventHandled( false );
+
+    // If a device key then skip ecore_imf_context_filter_event.
+    if ( ! KeyLookup::IsDeviceButton( keyEvent->keyname ) )
+    {
+      Ecore_IMF_Context* imfContext = NULL;
+      Dali::ImfManager imfManager( ImfManager::Get() );
+      if ( imfManager )
+      {
+        imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+      }
+
+      if ( imfContext )
+      {
+        // We're consuming key down event so we have to pass to IMF so that it can parse it as well.
+        Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
+        ecoreKeyDownEvent.keyname   = keyEvent->keyname;
+        ecoreKeyDownEvent.key       = keyEvent->key;
+        ecoreKeyDownEvent.string    = keyEvent->string;
+        ecoreKeyDownEvent.compose   = keyEvent->compose;
+        ecoreKeyDownEvent.timestamp = keyEvent->timestamp;
+        ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
+        ecoreKeyDownEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+        ecoreKeyDownEvent.dev_name  = "";
+
+        eventHandled = ecore_imf_context_filter_event( imfContext,
+                                                       ECORE_IMF_EVENT_KEY_DOWN,
+                                                       (Ecore_IMF_Event *) &ecoreKeyDownEvent );
+
+        // If the event has not been handled by IMF then check if we should reset our IMF context
+        if( !eventHandled )
+        {
+          if ( !strcmp( keyEvent->keyname, "Escape"   ) ||
+               !strcmp( keyEvent->keyname, "Return"   ) ||
+               !strcmp( keyEvent->keyname, "KP_Enter" ) )
+          {
+            ecore_imf_context_reset( imfContext );
+          }
+        }
+      }
+    }
+
+    // If the event wasn't handled then we should send a key event.
+    if ( !eventHandled )
+    {
+      if ( keyEvent->window == handler->mImpl->mWindow )
+      {
+        std::string keyName( keyEvent->keyname );
+        std::string keyString( "" );
+        int keyCode = ecore_x_keysym_keycode_get(keyEvent->keyname);
+        int modifier( keyEvent->modifiers );
+        unsigned long time = keyEvent->timestamp;
+
+        // Ensure key event string is not NULL as keys like SHIFT have a null string.
+        if ( keyEvent->string )
+        {
+          keyString = keyEvent->string;
+        }
+
+        KeyEvent keyEvent(keyName, keyString, keyCode, modifier, time, KeyEvent::Down);
+        handler->SendEvent( keyEvent );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a key up is received.
+   */
+  static Eina_Bool EcoreEventKeyUp( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventKeyUp \n" );
+
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_Event_Key *keyEvent( (Ecore_Event_Key*)event );
+    bool eventHandled( false );
+
+    // Menu, home, back button must skip ecore_imf_context_filter_event.
+    static const char* menuKeyName = KeyLookup::GetKeyName( DALI_KEY_MENU );
+    static const char* homeKeyName = KeyLookup::GetKeyName( DALI_KEY_HOME );
+    static const char* backKeyName = KeyLookup::GetKeyName( DALI_KEY_BACK );
+    if ( ( menuKeyName && strcmp( keyEvent->keyname, menuKeyName ) != 0 ) &&
+         ( homeKeyName && strcmp( keyEvent->keyname, homeKeyName ) != 0 ) &&
+         ( backKeyName && strcmp( keyEvent->keyname, backKeyName ) != 0 ) )
+    {
+      Ecore_IMF_Context* imfContext = NULL;
+      Dali::ImfManager imfManager( ImfManager::Get() );
+      if ( imfManager )
+      {
+        imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+      }
+
+      if ( imfContext )
+      {
+        // We're consuming key up event so we have to pass to IMF so that it can parse it as well.
+        Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
+        ecoreKeyUpEvent.keyname   = keyEvent->keyname;
+        ecoreKeyUpEvent.key       = keyEvent->key;
+        ecoreKeyUpEvent.string    = keyEvent->string;
+        ecoreKeyUpEvent.compose   = keyEvent->compose;
+        ecoreKeyUpEvent.timestamp = keyEvent->timestamp;
+        ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier ( keyEvent->modifiers );
+        ecoreKeyUpEvent.locks     = (Ecore_IMF_Keyboard_Locks) ECORE_IMF_KEYBOARD_LOCK_NONE;
+        ecoreKeyUpEvent.dev_name  = "";
+
+        eventHandled = ecore_imf_context_filter_event( imfContext,
+                                                       ECORE_IMF_EVENT_KEY_UP,
+                                                       (Ecore_IMF_Event *) &ecoreKeyUpEvent );
+      }
+    }
+
+    // If the event wasn't handled then we should send a key event.
+    if ( !eventHandled )
+    {
+      if ( keyEvent->window == handler->mImpl->mWindow )
+      {
+        std::string keyName( keyEvent->keyname );
+        std::string keyString( "" );
+        int keyCode = ecore_x_keysym_keycode_get(keyEvent->keyname);
+        int modifier( keyEvent->modifiers );
+        unsigned long time( keyEvent->timestamp );
+
+        // Ensure key event string is not NULL as keys like SHIFT have a null string.
+        if ( keyEvent->string )
+        {
+          keyString = keyEvent->string;
+        }
+
+        KeyEvent keyEvent(keyName, keyString, keyCode, modifier, time, KeyEvent::Up);
+        handler->SendEvent( keyEvent );
+
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Window Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when the window gains focus.
+   */
+  static Eina_Bool EcoreEventWindowFocusIn( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Window_Focus_In* focusInEvent( (Ecore_X_Event_Window_Focus_In*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventWindowFocusIn \n" );
+
+    // If the window gains focus and we hid the keyboard then show it again.
+    if ( focusInEvent->win == handler->mImpl->mWindow )
+    {
+      DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT EcoreEventWindowFocusIn - >>WindowFocusGained \n" );
+
+      if ( ImfManager::IsAvailable() /* Only get the ImfManager if it's available as we do not want to create it */ )
+      {
+        Dali::ImfManager imfManager( ImfManager::Get() );
+        if ( imfManager )
+        {
+          ImfManager& imfManagerImpl( ImfManager::GetImplementation( imfManager ) );
+          if( imfManagerImpl.RestoreAfterFocusLost() )
+          {
+            imfManagerImpl.Activate();
+          }
+        }
+      }
+      // No need to connect callbacks as KeyboardStatusChanged will be called.
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window loses focus.
+   */
+  static Eina_Bool EcoreEventWindowFocusOut( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Window_Focus_Out* focusOutEvent( (Ecore_X_Event_Window_Focus_Out*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "EVENT >>EcoreEventWindowFocusOut \n" );
+
+    // If the window loses focus then hide the keyboard.
+    if ( focusOutEvent->win == handler->mImpl->mWindow )
+    {
+      if ( ImfManager::IsAvailable() /* Only get the ImfManager if it's available as we do not want to create it */ )
+      {
+        Dali::ImfManager imfManager( ImfManager::Get() );
+        if ( imfManager )
+        {
+          ImfManager& imfManagerImpl( ImfManager::GetImplementation( imfManager ) );
+          if( imfManagerImpl.RestoreAfterFocusLost() )
+          {
+            imfManagerImpl.Deactivate();
+          }
+        }
+      }
+
+      // Clipboard don't support that whether clipboard is shown or not. Hide clipboard.
+      Dali::Clipboard clipboard = Clipboard::Get();
+      clipboard.HideClipboard();
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window is damaged.
+   */
+  static Eina_Bool EcoreEventWindowDamaged(void *data, int type, void *event)
+  {
+    Ecore_X_Event_Window_Damage* windowDamagedEvent( (Ecore_X_Event_Window_Damage*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if( windowDamagedEvent->win == handler->mImpl->mWindow )
+    {
+      DamageArea area;
+      area.x = windowDamagedEvent->x;
+      area.y = windowDamagedEvent->y;
+      area.width = windowDamagedEvent->w;
+      area.height = windowDamagedEvent->h;
+
+      handler->SendEvent( area );
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the window properties are changed.
+   * We are only interested in the font change.
+   */
+
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Drag & Drop Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called when a dragged item enters our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndEnter( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO( gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndEnter\n" );
+
+    Ecore_X_Event_Xdnd_Enter* enterEvent( (Ecore_X_Event_Xdnd_Enter*) event );
+    EventHandler* handler( (EventHandler*)data );
+    Ecore_X_Window window ( handler->mImpl->mWindow );
+
+    if ( enterEvent->win == window )
+    {
+      DragAndDropDetectorPtr dndDetector( handler->mDragAndDropDetector );
+
+      // Check whether the Drag & Drop detector has Drag & Drop behaviour enabled before we accept.
+      if ( dndDetector && dndDetector->IsEnabled() )
+      {
+        // Tell Ecore that we want to enable drop in the entire window.
+        Ecore_X_Rectangle rect;
+        rect.x = rect.y = 0;
+        ecore_x_window_geometry_get( window, NULL, NULL, (int*)&rect.width, (int*)&rect.height );
+
+        // Tell Ecore that we are able to process a drop.
+        ecore_x_dnd_send_status( EINA_TRUE, EINA_FALSE, rect, ECORE_X_ATOM_XDND_DROP );
+
+        // Register the required atoms and types.
+        ecore_x_dnd_actions_set( window, DRAG_AND_DROP_ATOMS, DRAG_AND_DROP_ATOMS_NUMBER );
+        ecore_x_dnd_types_set(   window, DRAG_AND_DROP_TYPES, DRAG_AND_DROP_TYPES_NUMBER );
+
+        // Request to get the content from Ecore.
+        ecore_x_selection_xdnd_request( window, ECORE_X_SELECTION_TARGET_UTF8_STRING );
+
+        DALI_LOG_INFO( gDragAndDropLogFilter, Debug::General, "EcoreEventDndEnter: Requesting Drag & Drop\n" );
+
+        // Clear the previous content
+        dndDetector->ClearContent();
+
+        // Emit the entered signal
+        dndDetector->EmitEnteredSignal();
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved within our window.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndPosition( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndPosition\n" );
+
+    Ecore_X_Event_Xdnd_Position* positionEvent( (Ecore_X_Event_Xdnd_Position*) event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( positionEvent->win == handler->mImpl->mWindow )
+    {
+      DragAndDropDetectorPtr dndDetector( handler->mDragAndDropDetector );
+
+      // If we have a detector then update its latest position.
+      if ( dndDetector )
+      {
+        DALI_LOG_INFO(gDragAndDropLogFilter, Debug::General, "EcoreEventDndPosition: position ( %d x %d )\n", positionEvent->position.x, positionEvent->position.y );
+        dndDetector->SetPosition( Vector2( positionEvent->position.x, positionEvent->position.y ));
+        dndDetector->EmitMovedSignal();
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item leaves our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndLeave( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndLeave\n" );
+
+    Ecore_X_Event_Xdnd_Leave* leaveEvent( (Ecore_X_Event_Xdnd_Leave*) event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( leaveEvent->win == handler->mImpl->mWindow )
+    {
+      DragAndDropDetectorPtr dndDetector( handler->mDragAndDropDetector );
+
+      // If we have a detector then clear its content and emit the exited-signal. Also tell Ecore that we have finished.
+      if ( dndDetector )
+      {
+        dndDetector->ClearContent();
+        dndDetector->EmitExitedSignal();
+
+        ecore_x_dnd_send_finished();
+
+        DALI_LOG_INFO( gDragAndDropLogFilter, Debug::General, "EcoreEventDndLeave: Finished\n" );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the dragged item is dropped within our window's bounds.
+   * This is when items are dragged INTO our window.
+   */
+  static Eina_Bool EcoreEventDndDrop( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndDrop\n" );
+
+    Ecore_X_Event_Xdnd_Drop* dropEvent ( (Ecore_X_Event_Xdnd_Drop*) event);
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( dropEvent->win == handler->mImpl->mWindow )
+    {
+      DragAndDropDetectorPtr dndDetector( handler->mDragAndDropDetector );
+
+      // Something has been dropped, inform the detector (if we have one) and tell Ecore that we have finished.
+      if ( dndDetector )
+      {
+        DALI_LOG_INFO(gDragAndDropLogFilter, Debug::General, "EcoreEventDndDrop: position ( %d x %d )\n", dropEvent->position.x, dropEvent->position.y );
+
+        dndDetector->SetPosition( Vector2( dropEvent->position.x, dropEvent->position.y ) );
+        dndDetector->EmitDroppedSignal();
+        ecore_x_dnd_send_finished();
+
+        DALI_LOG_INFO( gDragAndDropLogFilter, Debug::General, "EcoreEventDndDrop: Finished\n" );
+      }
+    }
+
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved from our window and the target window has done processing it.
+   * This is when items are dragged FROM our window.
+   */
+  static Eina_Bool EcoreEventDndFinished( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndFinished\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when a dragged item is moved from our window and the target window has sent us a status.
+   * This is when items are dragged FROM our window.
+   */
+  static Eina_Bool EcoreEventDndStatus( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gDragAndDropLogFilter, Debug::Concise, "EcoreEventDndStatus\n" );
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the client messages (i.e. the accessibility events) are received.
+   */
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Event_Client_Message* clientMessageEvent( (Ecore_X_Event_Client_Message*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if (clientMessageEvent->message_type == ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL)
+    {
+      if ( ( (unsigned int)clientMessageEvent->data.l[0] == handler->mImpl->mWindow ) && handler->mAccessibilityAdaptor )
+      {
+        AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( handler->mAccessibilityAdaptor ) );
+
+        if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_SCROLL)
+        {
+          // 2 finger touch & move, 2 finger flick
+
+          // mouse state : e->data.l[2] (0: mouse down, 1: mouse move, 2: mouse up)
+          // x : e->data.l[3]
+          // y : e->data.l[4]
+          TouchPoint::State state(TouchPoint::Down);
+
+          if ((unsigned int)clientMessageEvent->data.l[2] == 0)
+          {
+            state = TouchPoint::Down; // mouse down
+          }
+          else if ((unsigned int)clientMessageEvent->data.l[2] == 1)
+          {
+            state = TouchPoint::Motion; // mouse move
+          }
+          else if ((unsigned int)clientMessageEvent->data.l[2] == 2)
+          {
+            state = TouchPoint::Up; // mouse up
+          }
+          else
+          {
+            state = TouchPoint::Interrupted; // error
+          }
+
+          DALI_LOG_INFO(gClientMessageLogFilter, Debug::General,
+            "[%s:%d] [%d] %d, %d\n", __FUNCTION__, __LINE__,
+            (unsigned int)clientMessageEvent->data.l[2],
+            (unsigned int)clientMessageEvent->data.l[3], (unsigned int)clientMessageEvent->data.l[4]);
+
+          // Send touch event to accessibility adaptor.
+          TouchPoint point( 0, state, (float)clientMessageEvent->data.l[3], (float)clientMessageEvent->data.l[4] );
+
+          // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
+          accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() );
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_MOUSE)
+        {
+          // 1 finger double tap and hold
+
+          // mouse state : e->data.l[2] (0: mouse down, 1: mouse move, 2: mouse up)
+          // x : e->data.l[3]
+          // y : e->data.l[4]
+          TouchPoint::State state(TouchPoint::Down);
+
+          if ((unsigned int)clientMessageEvent->data.l[2] == 0)
+          {
+            state = TouchPoint::Down; // mouse down
+          }
+          else if ((unsigned int)clientMessageEvent->data.l[2] == 1)
+          {
+            state = TouchPoint::Motion; // mouse move
+          }
+          else if ((unsigned int)clientMessageEvent->data.l[2] == 2)
+          {
+            state = TouchPoint::Up; // mouse up
+          }
+          else
+          {
+            state = TouchPoint::Interrupted; // error
+          }
+
+          DALI_LOG_INFO(gClientMessageLogFilter, Debug::General,
+            "[%s:%d] [%d] %d, %d\n", __FUNCTION__, __LINE__,
+            (unsigned int)clientMessageEvent->data.l[2],
+            (unsigned int)clientMessageEvent->data.l[3], (unsigned int)clientMessageEvent->data.l[4]);
+
+          // Send touch event to accessibility adaptor.
+          TouchPoint point( 0, state, (float)clientMessageEvent->data.l[3], (float)clientMessageEvent->data.l[4] );
+
+          // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
+          accessibilityAdaptor->HandleActionTouchEvent( point, GetCurrentMilliSeconds() );
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_BACK)
+        {
+          // 2 finger circle draw, do back
+          accessibilityAdaptor->HandleActionBackEvent();
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_NEXT)
+        {
+          // one finger flick down
+          // focus next object
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionNextEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_PREV)
+        {
+          // one finger flick up
+          // focus previous object
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionPreviousEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ACTIVATE)
+        {
+          // one finger double tap
+          // same as one finger tap in normal mode (i.e. execute focused actor)
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionActivateEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ)
+        {
+          // one finger tap
+          // focus & read an actor at ( e->data.l[2], e->data.l[3] ) position according to finger
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionReadEvent((unsigned int)clientMessageEvent->data.l[2], (unsigned int)clientMessageEvent->data.l[3], true /* allow read again*/);
+          }
+        }
+#if defined(DALI_PROFILE_MOBILE)
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_OVER)
+        {
+          // one finger tap & move
+          // mouse state : e->data.l[2] (0: mouse down, 1: mouse move, 2: mouse up)
+          // x : e->data.l[3]
+          // y : e->data.l[4]
+          // focus & read an actor at (x, y) position according to finger
+          if(accessibilityAdaptor && (unsigned int)clientMessageEvent->data.l[2] == 1 /*only work for move event*/)
+          {
+            accessibilityAdaptor->HandleActionReadEvent((unsigned int)clientMessageEvent->data.l[3], (unsigned int)clientMessageEvent->data.l[4], false /* not allow read again*/);
+          }
+        }
+#endif
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_NEXT)
+        {
+          // one finger flick right
+          // focus next object
+           if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionReadNextEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_READ_PREV)
+        {
+          // one finger flick left
+          // focus previous object
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionReadPreviousEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_UP)
+        {
+          // double down and move (right, up)
+          // change slider value
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionUpEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DOWN)
+        {
+          // double down and move (left, down)
+          // change slider value
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionDownEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_ENABLE)
+        {
+           if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionEnableEvent();
+          }
+        }
+        else if((unsigned int)clientMessageEvent->data.l[1] == ECORE_X_ATOM_E_ILLUME_ACCESS_ACTION_DISABLE)
+        {
+          if(accessibilityAdaptor)
+          {
+            accessibilityAdaptor->HandleActionDisableEvent();
+          }
+        }
+        // TODO: some more actions could be added later
+      }
+    }
+    else if(clientMessageEvent->message_type == ecore_x_atom_get(CLIPBOARD_ATOM))
+    {
+      std::string message(clientMessageEvent->data.b);
+      if( message == CLIPBOARD_SET_OWNER_MESSAGE)
+      {
+        // Claim the ownership of the SECONDARY selection.
+        ecore_x_selection_secondary_set(handler->mImpl->mWindow, "", 1);
+
+        // Show the clipboard window
+        Dali::Clipboard clipboard = Dali::Clipboard::Get();
+        clipboard.ShowClipboard();
+      }
+    }
+    else if( clientMessageEvent->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_PREPARE )
+    {
+      RotationEvent rotationEvent;
+      rotationEvent.angle      = static_cast<int>(clientMessageEvent->data.l[1]);
+      rotationEvent.winResize  = static_cast<int>(clientMessageEvent->data.l[2]);
+      rotationEvent.width      = static_cast<int>(clientMessageEvent->data.l[3]);
+      rotationEvent.height     = static_cast<int>(clientMessageEvent->data.l[4]);
+      handler->SendRotationPrepareEvent( rotationEvent );
+    }
+    else if( clientMessageEvent->message_type == ECORE_X_ATOM_E_WINDOW_ROTATION_CHANGE_REQUEST )
+    {
+      handler->SendRotationRequestEvent();
+    }
+
+#endif // DALI_PROFILE_UBUNTU
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // ElDBus Accessibility Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  // Callback for Ecore ElDBus accessibility events.
+  static void OnEcoreElDBusAccessibilityNotification( void *context EINA_UNUSED, const Eldbus_Message *message )
+  {
+    EventHandler* handler = static_cast< EventHandler* >( context );
+    // Ignore any accessibility events when paused.
+    if( handler->mPaused )
+    {
+      return;
+    }
+
+    if ( !handler->mAccessibilityAdaptor )
+    {
+      DALI_LOG_ERROR( "Invalid accessibility adaptor\n" );
+      return;
+    }
+
+    AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( handler->mAccessibilityAdaptor ) );
+    if ( !accessibilityAdaptor )
+    {
+      DALI_LOG_ERROR( "Cannot access accessibility adaptor\n" );
+      return;
+    }
+
+    const char *gestureName;
+    int xS, yS, xE, yE;
+    unsigned int state;
+
+    // The string defines the arg-list's respective types.
+    if( !eldbus_message_arguments_get( message, "siiiiu", &gestureName, &xS, &yS, &xE, &yE, &state ) )
+    {
+      DALI_LOG_ERROR( "OnEcoreElDBusAccessibilityNotification: Error getting arguments\n" );
+    }
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Name: %s  Args: %d,%d,%d,%d  State: %d\n", gestureName, xS, yS, xE, yE );
+
+    unsigned int fingers = 0;
+    char* stringPosition = ( char* )gestureName;
+
+    // Check how many fingers the gesture uses.
+    for( unsigned int i = 0; i < FingerCountStringsTotal; ++i )
+    {
+      unsigned int matchLength = strlen( ElDBusAccessibilityFingerCountStrings[ i ] );
+      if( strncmp( gestureName, ElDBusAccessibilityFingerCountStrings[ i ], matchLength ) == 0 )
+      {
+        fingers = i + 1;
+        stringPosition += matchLength;
+        break;
+      }
+    }
+
+    if( fingers == 0 )
+    {
+      // Error: invalid gesture.
+      return;
+    }
+
+    GestureType gestureType = GESTURE_TYPE_NONE;
+    SubGestureType subGestureType = SUB_GESTURE_TYPE_NONE;
+    GestureDirection direction = GESTURE_DIRECTION_NONE;
+
+    // Check for full gesture type names first.
+    for( unsigned int i = 0; i < FullEventTypeStringsTotal; ++i )
+    {
+      unsigned int matchLength = strlen( ElDBusAccessibilityFullEventTypeStrings[ i ].name );
+      if( strncmp( stringPosition, ElDBusAccessibilityFullEventTypeStrings[ i ].name, matchLength ) == 0 )
+      {
+        gestureType = ElDBusAccessibilityFullEventTypeStrings[ i ].type;
+        break;
+      }
+    }
+
+    // If we didn't find a full gesture, check for sub gesture type names.
+    if( gestureType == GESTURE_TYPE_NONE )
+    {
+      // No full gesture name found, look for partial types.
+      for( unsigned int i = 0; i < DirectionalEventTypeStringsTotal; ++i )
+      {
+        unsigned int matchLength = strlen( ElDBusAccessibilityDirectionalEventTypeStrings[ i ].name );
+        if( strncmp( stringPosition, ElDBusAccessibilityDirectionalEventTypeStrings[ i ].name, matchLength ) == 0 )
+        {
+          subGestureType = ElDBusAccessibilityDirectionalEventTypeStrings[ i ].type;
+          stringPosition += matchLength;
+        break;
+        }
+      }
+
+      if( subGestureType == SUB_GESTURE_TYPE_NONE )
+      {
+        // ERROR: Gesture not recognised.
+        return;
+      }
+
+      // If the gesture was a sub type, get it's respective direction.
+      for( unsigned int i = 0; i < DirectionStringsTotal; ++i )
+      {
+        unsigned int matchLength = strlen( ElDBusAccessibilityDirectionStrings[ i ].name );
+        if( strncmp( stringPosition, ElDBusAccessibilityDirectionStrings[ i ].name, matchLength ) == 0 )
+        {
+          direction = ElDBusAccessibilityDirectionStrings[ i ].direction;
+          stringPosition += matchLength;
+          break;
+        }
+      }
+
+      if( direction == GESTURE_DIRECTION_NONE )
+      {
+        // ERROR: Gesture not recognised.
+        return;
+      }
+    }
+
+    // Action the detected gesture here.
+    if( gestureType != GESTURE_TYPE_NONE )
+    {
+      DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Fingers: %d  Gesture type: %d\n", fingers, gestureType );
+    }
+    else
+    {
+      DALI_LOG_INFO( gImfLogging, Debug::General, "Got gesture: Fingers: %d  Gesture sub type: %d Gesture direction: %d\n",
+        fingers, subGestureType, direction );
+    }
+
+    // Create a touch point object.
+    TouchPoint::State touchPointState( TouchPoint::Down );
+    if ( state == 0 )
+    {
+      touchPointState = TouchPoint::Down; // Mouse down.
+    }
+    else if ( state == 1 )
+    {
+      touchPointState = TouchPoint::Motion; // Mouse move.
+    }
+    else if ( state == 2 )
+    {
+      touchPointState = TouchPoint::Up; // Mouse up.
+    }
+    else
+    {
+      touchPointState = TouchPoint::Interrupted; // Error.
+    }
+
+    // Send touch event to accessibility adaptor.
+    TouchPoint point( 0, touchPointState, (float)xS, (float)yS );
+
+    // Perform actions based on received gestures.
+    // Note: This is seperated from the reading so we can (in future)
+    // have other input readers without changing the below code.
+    switch( fingers )
+    {
+      case 1:
+      {
+        if( gestureType == GESTURE_TYPE_SINGLE_TAP || ( gestureType == GESTURE_TYPE_HOVER && touchPointState == TouchPoint::Motion ) )
+        {
+          // Focus, read out.
+          accessibilityAdaptor->HandleActionReadEvent( (unsigned int)xS, (unsigned int)yS, true /* allow read again */ );
+        }
+        else if( gestureType == GESTURE_TYPE_DOUBLE_TAP )
+        {
+          if( false ) // TODO: how to detect double tap + hold?
+          {
+            // Move or drag icon / view more options for selected items.
+            // accessibilityAdaptor->HandleActionTouchEvent( point, GetCurrentMilliSeconds() );
+          }
+          else
+          {
+            // Activate selected item / active edit mode.
+            accessibilityAdaptor->HandleActionActivateEvent();
+          }
+        }
+        else if( gestureType == GESTURE_TYPE_TRIPLE_TAP )
+        {
+          // Zoom
+          accessibilityAdaptor->HandleActionZoomEvent();
+        }
+        else if( subGestureType == SUB_GESTURE_TYPE_FLICK )
+        {
+          if( direction == GESTURE_DIRECTION_LEFT )
+          {
+            // Move to previous item.
+            accessibilityAdaptor->HandleActionReadPreviousEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_RIGHT )
+          {
+            // Move to next item.
+            accessibilityAdaptor->HandleActionReadNextEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_UP )
+          {
+            // Move to next item.
+            accessibilityAdaptor->HandleActionPreviousEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_DOWN )
+          {
+            // Move to next item.
+            accessibilityAdaptor->HandleActionNextEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_LEFT_RETURN )
+          {
+            // Scroll up to the previous page
+            accessibilityAdaptor->HandleActionPageUpEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_RIGHT_RETURN )
+          {
+            // Scroll down to the next page
+            accessibilityAdaptor->HandleActionPageDownEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_UP_RETURN )
+          {
+            // Move to the first item on screen
+            accessibilityAdaptor->HandleActionMoveToFirstEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_DOWN_RETURN )
+          {
+            // Move to the last item on screen
+            accessibilityAdaptor->HandleActionMoveToLastEvent();
+          }
+        }
+        break;
+      }
+
+      case 2:
+      {
+        if( gestureType == GESTURE_TYPE_HOVER )
+        {
+          // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
+          accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() );
+        }
+        else if( gestureType == GESTURE_TYPE_SINGLE_TAP )
+        {
+          // Pause/Resume current speech
+          accessibilityAdaptor->HandleActionReadPauseResumeEvent();
+        }
+        else if( gestureType == GESTURE_TYPE_DOUBLE_TAP )
+        {
+          // Start/Stop current action
+          accessibilityAdaptor->HandleActionStartStopEvent();
+        }
+        else if( gestureType == GESTURE_TYPE_TRIPLE_TAP )
+        {
+          // Read information from indicator
+          accessibilityAdaptor->HandleActionReadIndicatorInformationEvent();
+        }
+        else if( subGestureType == SUB_GESTURE_TYPE_FLICK )
+        {
+          if( direction == GESTURE_DIRECTION_LEFT )
+          {
+            // Scroll left to the previous page
+            accessibilityAdaptor->HandleActionPageLeftEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_RIGHT )
+          {
+            // Scroll right to the next page
+            accessibilityAdaptor->HandleActionPageRightEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_UP )
+          {
+            // Scroll up the list.
+            accessibilityAdaptor->HandleActionScrollUpEvent();
+          }
+          else if( direction == GESTURE_DIRECTION_DOWN )
+          {
+            // Scroll down the list.
+            accessibilityAdaptor->HandleActionScrollDownEvent();
+          }
+        }
+        break;
+      }
+
+      case 3:
+      {
+        if( gestureType == GESTURE_TYPE_SINGLE_TAP )
+        {
+          // Read from top item on screen continuously.
+          accessibilityAdaptor->HandleActionReadFromTopEvent();
+        }
+        else if( gestureType == GESTURE_TYPE_DOUBLE_TAP )
+        {
+          // Read from next item continuously.
+          accessibilityAdaptor->HandleActionReadFromNextEvent();
+        }
+        break;
+      }
+    }
+  }
+
+  // Callback for to set up Ecore ElDBus for accessibility callbacks.
+  static void EcoreElDBusInitialisation( void *handle, const Eldbus_Message *message, Eldbus_Pending *pending EINA_UNUSED )
+  {
+    Eldbus_Object *object;
+    Eldbus_Proxy *manager;
+    const char *a11yBusAddress = NULL;
+    EventHandler* handler( (EventHandler*)handle );
+
+    // The string defines the arg-list's respective types.
+    if( !eldbus_message_arguments_get( message, "s", &a11yBusAddress ) )
+    {
+      DALI_LOG_ERROR( "EcoreElDBusInitialisation: Error getting arguments\n" );
+    }
+
+    DALI_LOG_INFO( gImfLogging, Debug::General, "Ecore ElDBus Accessibility address: %s\n", a11yBusAddress );
+
+    handler->mImpl->mA11yConnection = eldbus_address_connection_get( a11yBusAddress );
+
+    object = eldbus_object_get( handler->mImpl->mA11yConnection, BUS, PATH );
+    manager = eldbus_proxy_get( object, INTERFACE );
+
+    // Pass the callback data through to the signal handler.
+    eldbus_proxy_signal_handler_add( manager, SIGNAL, OnEcoreElDBusAccessibilityNotification, handle );
+  }
+#endif // DALI_ELDBUS_AVAILABLE
+
+  /**
+   * Called when the source window notifies us the content in clipboard is selected.
+   */
+  static Eina_Bool EcoreEventSelectionClear( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventSelectionClear\n" );
+    Ecore_X_Event_Selection_Clear* selectionClearEvent( (Ecore_X_Event_Selection_Clear*) event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( selectionClearEvent->win == handler->mImpl->mWindow )
+    {
+      if ( selectionClearEvent->selection == ECORE_X_SELECTION_SECONDARY )
+      {
+        // Request to get the content from Ecore.
+        ecore_x_selection_secondary_request(selectionClearEvent->win, ECORE_X_SELECTION_TARGET_TEXT);
+      }
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+  /**
+   * Called when the source window sends us about the selected content.
+   * For example, when dragged items are dragged INTO our window or when items are selected in the clipboard.
+   */
+  static Eina_Bool EcoreEventSelectionNotify( void* data, int type, void* event )
+  {
+    DALI_LOG_INFO(gSelectionEventLogFilter, Debug::Concise, "EcoreEventSelectionNotify\n" );
+
+    Ecore_X_Event_Selection_Notify* selectionNotifyEvent( (Ecore_X_Event_Selection_Notify*) event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if ( selectionNotifyEvent->win == handler->mImpl->mWindow )
+    {
+      Ecore_X_Selection_Data* selectionData( (Ecore_X_Selection_Data*) selectionNotifyEvent->data );
+      if ( selectionData->data )
+      {
+        if ( selectionNotifyEvent->selection == ECORE_X_SELECTION_XDND )
+        {
+          DragAndDropDetectorPtr dndDetector( handler->mDragAndDropDetector );
+
+          // We have got the content that is to be dropped, inform the DndListener (if we have one).
+          if ( dndDetector )
+          {
+            std::string content( (char*) selectionData->data, selectionData->length );
+            dndDetector->SetContent( content );
+
+            DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "EcoreEventSelectionNotify: Content(%d):\n" , selectionData->length );
+            DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "======================================\n" );
+            DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "%s\n", selectionData->data );
+            DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "======================================\n" );
+          }
+        }
+        else if ( selectionNotifyEvent->selection == ECORE_X_SELECTION_SECONDARY )
+        {
+          // We have got the selected content, inform the clipboard event listener (if we have one).
+          if ( handler->mClipboardEventNotifier )
+          {
+            ClipboardEventNotifier& clipboardEventNotifier( ClipboardEventNotifier::GetImplementation( handler->mClipboardEventNotifier ) );
+            std::string content( (char*) selectionData->data, selectionData->length );
+            clipboardEventNotifier.SetContent( content );
+            clipboardEventNotifier.EmitContentSelectedSignal();
+          }
+
+          // Claim the ownership of the SECONDARY selection.
+          ecore_x_selection_secondary_set(handler->mImpl->mWindow, "", 1);
+
+          DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "EcoreEventSelectionNotify: Content(%d):\n" , selectionData->length );
+          DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "======================================\n" );
+          DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "%s\n", selectionData->data );
+          DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "======================================\n" );
+        }
+      }
+    }
+    return ECORE_CALLBACK_PASS_ON;
+  }
+
+
+#ifndef DALI_PROFILE_UBUNTU
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Font Callbacks
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   * Called when a font name is changed.
+   */
+  static void VconfNotifyFontNameChanged( keynode_t* node, void* data )
+  {
+    EventHandler* handler = static_cast<EventHandler*>( data );
+    handler->SendEvent( StyleChange::DEFAULT_FONT_CHANGE );
+  }
+
+  /**
+   * Called when a font size is changed.
+   */
+  static void VconfNotifyFontSizeChanged( keynode_t* node, void* data )
+  {
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::Verbose, "VconfNotifyFontSizeChanged\n" );
+    EventHandler* handler = static_cast<EventHandler*>( data );
+    handler->SendEvent( StyleChange::DEFAULT_FONT_SIZE_CHANGE );
+  }
+#endif // DALI_PROFILE_UBUNTU
+
+  // Data
+  EventHandler* mHandler;
+  std::vector<Ecore_Event_Handler*> mEcoreEventHandler;
+  Ecore_X_Window mWindow;
+  int mXiDeviceId;
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Connection* mSessionConnection;
+  Eldbus_Connection* mA11yConnection;
+#endif
+};
+
+EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector )
+: mCoreEventInterface( coreEventInterface ),
+  mGestureManager( gestureManager ),
+  mStyleMonitor( StyleMonitor::Get() ),
+  mDamageObserver( damageObserver ),
+  mRotationObserver( NULL ),
+  mDragAndDropDetector( dndDetector ),
+  mAccessibilityAdaptor( AccessibilityAdaptor::Get() ),
+  mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
+  mClipboard( Clipboard::Get() ),
+  mImpl( NULL ),
+  mPaused( false )
+{
+  Ecore_X_Window window = 0;
+
+  // this code only works with the EcoreX11 RenderSurface so need to downcast
+  ECore::WindowRenderSurface* ecoreSurface = dynamic_cast< ECore::WindowRenderSurface* >( surface );
+  if( ecoreSurface )
+  {
+    // enable multi touch
+    window = ecoreSurface->GetXWindow();
+  }
+
+  mImpl = new Impl(this, window);
+}
+
+EventHandler::~EventHandler()
+{
+  delete mImpl;
+
+  mGestureManager.Stop();
+}
+
+void EventHandler::SendEvent(TouchPoint& point, unsigned long timeStamp)
+{
+  if(timeStamp < 1)
+  {
+    timeStamp = GetCurrentMilliSeconds();
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if(type != Integration::TouchEventCombiner::DispatchNone )
+  {
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.deviceId, point.state, point.local.x, point.local.y);
+
+    // First the touch and/or hover event & related gesture events are queued
+    if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( touchEvent );
+      mGestureManager.SendEvent(touchEvent);
+    }
+
+    if(type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( hoverEvent );
+    }
+
+    // Next the events are processed with a single call into Core
+    mCoreEventInterface.ProcessCoreEvents();
+  }
+}
+
+void EventHandler::SendEvent(KeyEvent& keyEvent)
+{
+  Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
+  if ( physicalKeyboard )
+  {
+    if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ) )
+    {
+      GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
+    }
+  }
+
+  // Create KeyEvent and send to Core.
+  Integration::KeyEvent event(keyEvent.keyPressedName, keyEvent.keyPressed, keyEvent.keyCode,
+  keyEvent.keyModifier, keyEvent.time, static_cast<Integration::KeyEvent::State>(keyEvent.state));
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendWheelEvent( WheelEvent& wheelEvent )
+{
+  // Create WheelEvent and send to Core.
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendEvent( StyleChange::Type styleChange )
+{
+  DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
+  GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
+}
+
+void EventHandler::SendEvent( const DamageArea& area )
+{
+  mDamageObserver.OnDamaged( area );
+}
+
+void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationPrepare( event );
+  }
+}
+
+void EventHandler::SendRotationRequestEvent( )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationRequest( );
+  }
+}
+
+void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)
+{
+  SendEvent(point, timeStamp);
+}
+
+void EventHandler::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  SendWheelEvent( wheelEvent );
+}
+
+void EventHandler::FeedKeyEvent( KeyEvent& event )
+{
+  SendEvent( event );
+}
+
+void EventHandler::FeedEvent( Integration::Event& event )
+{
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Reset()
+{
+  mCombiner.Reset();
+
+  // Any touch listeners should be told of the interruption.
+  Integration::TouchEvent event;
+  TouchPoint point(0, TouchPoint::Interrupted, 0, 0);
+  event.AddPoint( point );
+
+  // First the touch event & related gesture events are queued
+  mCoreEventInterface.QueueCoreEvent( event );
+  mGestureManager.SendEvent( event );
+
+  // Next the events are processed with a single call into Core
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Pause()
+{
+  mPaused = true;
+  Reset();
+}
+
+void EventHandler::Resume()
+{
+  mPaused = false;
+  Reset();
+}
+
+void EventHandler::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
+{
+  mDragAndDropDetector = detector;
+}
+
+void EventHandler::SetRotationObserver( RotationObserver* observer )
+{
+  mRotationObserver = observer;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/ecore-x-render-surface-factory.cpp b/adaptors/x11/ecore-x-render-surface-factory.cpp
new file mode 100644 (file)
index 0000000..552ea12
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <pixmap-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+DALI_EXPORT_API PixmapRenderSurface* CreatePixmapSurface(
+  PositionSize       positionSize,
+  Any                surface,
+  const std::string& name,
+  bool               isTransparent)
+{
+  return new PixmapRenderSurface(positionSize, surface, name, isTransparent);
+}
+
+
+} // namespace ECore
+
+} // namespace Dali
+
+
+
diff --git a/adaptors/x11/ecore-x-render-surface-factory.h b/adaptors/x11/ecore-x-render-surface-factory.h
new file mode 100644 (file)
index 0000000..781bb85
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef __DALI_INTERNAL_ADAPTOR_ECORE_X_RENDER_SURFACE_FACTORY_H__
+#define __DALI_INTERNAL_ADAPTOR_ECORE_X_RENDER_SURFACE_FACTORY_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <native-buffer-pool.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+class RenderSurface;
+
+/**
+ * Surface factory function for pixmap
+ * A pixmap surface is created.
+ *
+ * @param [in] type the type of surface to create
+ * @param [in] positionSize the position and size of the surface to create
+ * @param [in] display X Pixmap to use, or null for default.
+ * @param [in] display X Display to use, or null for default.
+ * @param [in] name Name of surface passed in
+ * @param [in] isTransparent Whether the surface has an alpha channel
+ */
+RenderSurface* CreatePixmapSurface(
+  PositionSize       positionSize,
+  Any         surface,
+  Any         display,
+  const std::string& name,
+  bool               isTransparent );
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif //  __DALI_INTERNAL_ADAPTOR_ECORE_X_RENDER_SURFACE_FACTORY_H__
diff --git a/adaptors/x11/ecore-x-render-surface.cpp b/adaptors/x11/ecore-x-render-surface.cpp
new file mode 100644 (file)
index 0000000..e8e7d33
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "ecore-x-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <X11/extensions/Xfixes.h> // for damage notify
+#include <X11/extensions/Xdamage.h> // for damage notify
+
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <ecore-x-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_ECORE_X_RENDER_SURFACE");
+#endif
+
+namespace ECore
+{
+
+EcoreXRenderSurface::EcoreXRenderSurface(Dali::PositionSize positionSize,
+                                         Any surface,
+                                         const std::string& name,
+                                         bool isTransparent)
+: mPosition(positionSize),
+  mTitle(name),
+  mRenderNotification(NULL),
+  mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
+  mOwnSurface(false)
+{
+}
+
+void EcoreXRenderSurface::Init( Any surface )
+{
+  // see if there is a surface in Any surface
+  unsigned int surfaceId  = GetSurfaceId( surface );
+
+  // if the surface is empty, create a new one.
+  if ( surfaceId == 0 )
+  {
+    // we own the surface about to created
+    mOwnSurface = true;
+    CreateXRenderable();
+  }
+  else
+  {
+    // XLib should already be initialized so no point in calling XInitThreads
+    UseExistingRenderable( surfaceId );
+  }
+
+#ifdef DEBUG_ENABLED
+  // prints out 'INFO: DALI: new EcoreXRenderSurface, used existing surface xx
+  // we can not use LOG_INFO because the surface can be created before Dali Core is created.
+  printf( "INFO: DALI: new EcoreXRenderSurface, %s surface %X \n",
+          mOwnSurface?"created":"used existing",
+          GetDrawable() );
+#endif
+}
+
+EcoreXRenderSurface::~EcoreXRenderSurface()
+{
+}
+
+void EcoreXRenderSurface::SetRenderNotification(TriggerEventInterface* renderNotification)
+{
+  mRenderNotification = renderNotification;
+}
+
+Ecore_X_Window EcoreXRenderSurface::GetXWindow()
+{
+  return 0;
+}
+
+Ecore_X_Drawable EcoreXRenderSurface::GetDrawable()
+{
+  return 0;
+}
+
+PositionSize EcoreXRenderSurface::GetPositionSize() const
+{
+  return mPosition;
+}
+
+void EcoreXRenderSurface::MoveResize( Dali::PositionSize positionSize )
+{
+  // nothing to do in base class
+}
+
+void EcoreXRenderSurface::SetViewMode( ViewMode viewMode )
+{
+}
+
+unsigned int EcoreXRenderSurface::GetSurfaceId( Any surface ) const
+{
+  unsigned int surfaceId = 0;
+
+  if ( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) ||
+                          (surface.GetType() == typeid (Ecore_X_Window) ) )
+                        && "Surface type is invalid" );
+
+    if ( surface.GetType() == typeid (Ecore_X_Window) )
+    {
+      surfaceId = AnyCast<Ecore_X_Window>( surface );
+    }
+    else
+    {
+      surfaceId = AnyCast<XWindow>( surface );
+    }
+  }
+  return surfaceId;
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/x11/ecore-x-window-interface.cpp b/adaptors/x11/ecore-x-window-interface.cpp
new file mode 100644 (file)
index 0000000..25c310f
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "ecore-x-window-interface.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <ecore-x-types.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+namespace WindowInterface
+{
+// CONSTANTS
+const char* const CBHM_WINDOW = "CBHM_XWIN";
+
+Ecore_X_Window GetWindow()
+{
+  Ecore_X_Atom xAtomCbhm = ecore_x_atom_get( CBHM_WINDOW );
+
+  Ecore_X_Window xCbhmWin = 0;
+  unsigned char *buf = NULL;
+  int num = 0;
+  int ret = ecore_x_window_prop_property_get( 0, xAtomCbhm, XA_WINDOW, 0, &buf, &num );
+
+  if ( ret && num )
+  {
+    memcpy( &xCbhmWin, buf, sizeof( Ecore_X_Window ) );
+  }
+  if ( buf )
+  {
+    free( buf );
+  }
+
+  return xCbhmWin;
+}
+
+std::string GetWindowProperty( Ecore_X_Atom property, Ecore_X_Atom *xDataType, unsigned int num  )
+{
+   std::string data("");
+
+   if ( !property )
+   {
+      return data;
+   }
+
+   ecore_x_sync();
+
+   long unsigned int numRet = 0, bytes = 0;
+   int ret = 0, sizeRet;
+   unsigned int i;
+   unsigned char *propRet;
+   Ecore_X_Atom typeRet;
+
+   // X11 Function to get window property
+   ret = XGetWindowProperty( static_cast<Display*>(ecore_x_display_get()), // Display* X Server Connection
+                             GetWindow(),                                  // Window  window in question
+                             property,                                     // Atom  name of property
+                             num,                                          // long offset where required data is stored
+                             LONG_MAX,                                     // long length of data to retrieve
+                             False,                                        // Bool flag to delete data
+                             ecore_x_window_prop_any_type(),               // Atom atom id associated to property type
+                             (Atom *)&typeRet,                             // Atom actual_type_return, atom id property type
+                             &sizeRet,                                     // int* format of property
+                             &numRet,                                      // unsigned long*  number of items being returned in prop_return
+                             &bytes,                                       // unsigned long* remaining bytes if partial retrieval
+                             &propRet );                                   // unsigned char** return data
+   if ( ret != Success )
+   {
+     return data;
+   }
+
+   if ( !numRet )
+   {
+      XFree( propRet );
+      return data;
+   }
+
+   numRet--; // As propRet in XGetWindowProperty gets an extra 0 added for compatibility reasons.
+
+   switch ( sizeRet ) // Format returned by XGetWindowProperty int, short, long
+   {
+   case 8:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data += propRet[i];
+     }
+   }
+   break;
+
+   case 16:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data +=  ( ( unsigned short * )propRet )[i];
+     }
+   }
+   break;
+
+   case 32:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data += ( ( unsigned long * )propRet )[i];
+     }
+   }
+   break;
+   }
+
+   XFree( propRet );
+
+   if ( xDataType )
+   {
+     *xDataType = typeRet;
+   }
+
+   return data;
+  }
+
+void SendXEvent(Ecore_X_Display* display, Ecore_X_Window window, bool propagate,
+    long int eventMask, Ecore_X_Atom messageType, int messageFormat, const char *msg )
+{
+  XClientMessageEvent message;
+  memset(&message, 0, sizeof( message ) );
+  message.type = ClientMessage;
+  message.display = static_cast<Display*>( display );
+  message.message_type = messageType;
+  message.format = messageFormat;
+  message.window = window;
+  snprintf(message.data.b, 20, "%s", msg);
+
+  XSendEvent( static_cast<Display*>( display ), window, propagate, eventMask,( XEvent* )&message );
+}
+
+
+} // namespace WindowInterface
+
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/ecore-x-window-interface.h b/adaptors/x11/ecore-x-window-interface.h
new file mode 100644 (file)
index 0000000..e28fa28
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H__
+#define __DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <Ecore_X.h>
+#include <X11/Xlib.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+namespace WindowInterface
+{
+/**
+ * X11 Window interface, to separate X11 calls within adaptor.
+ */
+
+/**
+ * Gets the Ecore X Window
+ * @return window
+ */
+ Ecore_X_Window GetWindow();
+
+ /**
+  * Gets a specified X window property
+  * @param[in] property the required property id
+  * @param[in] xDataType the type
+  * @param[in] num the offset / index of the property
+  * @return string the property value
+  */
+ std::string GetWindowProperty( Ecore_X_Atom property, Ecore_X_Atom *xDataType, unsigned int num  );
+
+ /**
+  * Send an X Event
+  * @param[in] display target display
+  * @param[in] window target window
+  * @param[in] propagate to propagate to other windows
+  * @parma[in] eventMask event mask
+  * @param[in] messageType Ecore_X_Atom message type
+  * @param[in] messageFormat format of message
+  * @param[in] msg message to send
+  */
+ void SendXEvent(Ecore_X_Display* display, Ecore_X_Window window, bool propagate,
+                 long int eventMask, Ecore_X_Atom messageType, int messageFormat, const char *msg );
+
+} // namespace WindowInterface
+
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H__
diff --git a/adaptors/x11/egl-implementation-x.cpp b/adaptors/x11/egl-implementation-x.cpp
new file mode 100644 (file)
index 0000000..be06705
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <gl/egl-implementation.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <ecore-x-render-surface.h>
+#include <gl/gl-implementation.h>
+
+namespace
+{
+
+void PrintEglError( EGLint error )
+{
+  switch (error)
+  {
+    case EGL_BAD_DISPLAY:
+    {
+      DALI_LOG_ERROR("EGL_BAD_DISPLAY : Display is not an EGL display connection\n");
+      break;
+    }
+    case EGL_NOT_INITIALIZED:
+    {
+      DALI_LOG_ERROR("EGL_NOT_INITIALIZED : Display has not been initialized\n");
+      break;
+    }
+    case EGL_BAD_SURFACE:
+    {
+      DALI_LOG_ERROR("EGL_BAD_SURFACE : Draw or read is not an EGL surface\n");
+      break;
+    }
+    case EGL_BAD_CONTEXT:
+    {
+      DALI_LOG_ERROR("EGL_BAD_CONTEXT : Context is not an EGL rendering context\n");
+      break;
+    }
+    case EGL_BAD_MATCH:
+    {
+      DALI_LOG_ERROR("EGL_BAD_MATCH : Draw or read are not compatible with context, or if context is set to EGL_NO_CONTEXT and draw or read are not set to EGL_NO_SURFACE, or if draw or read are set to EGL_NO_SURFACE and context is not set to EGL_NO_CONTEXT\n");
+      break;
+    }
+    case EGL_BAD_ACCESS:
+    {
+      DALI_LOG_ERROR("EGL_BAD_ACCESS : Context is current to some other thread\n");
+      break;
+    }
+    case EGL_BAD_NATIVE_PIXMAP:
+    {
+      DALI_LOG_ERROR("EGL_BAD_NATIVE_PIXMAP : A native pixmap underlying either draw or read is no longer valid\n");
+      break;
+    }
+    case EGL_BAD_NATIVE_WINDOW:
+    {
+      DALI_LOG_ERROR("EGL_BAD_NATIVE_WINDOW : A native window underlying either draw or read is no longer valid\n");
+      break;
+    }
+    case EGL_BAD_CURRENT_SURFACE:
+    {
+      DALI_LOG_ERROR("EGL_BAD_CURRENT_SURFACE : The previous context has unflushed commands and the previous surface is no longer valid\n");
+      break;
+    }
+    case EGL_BAD_ALLOC:
+    {
+      DALI_LOG_ERROR("EGL_BAD_ALLOC : Allocation of ancillary buffers for draw or read were delayed until eglMakeCurrent is called, and there are not enough resources to allocate them\n");
+      break;
+    }
+    case EGL_CONTEXT_LOST:
+    {
+      DALI_LOG_ERROR("EGL_CONTEXT_LOST : If a power management event has occurred. The application must destroy all contexts and reinitialise OpenGL ES state and objects to continue rendering\n");
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Unknown error with code: %d\n", error);
+      break;
+    }
+  }
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#define TEST_EGL_ERROR(lastCommand) \
+{ \
+  EGLint err = eglGetError(); \
+  if (err != EGL_SUCCESS) \
+  { \
+    DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
+    PrintEglError(err); \
+    DALI_ASSERT_ALWAYS(0 && "EGL error"); \
+  } \
+}
+
+EglImplementation::EglImplementation()
+  : mEglNativeDisplay(0),
+    mEglNativeWindow(0),
+    mEglNativePixmap(0),
+    mEglDisplay(0),
+    mEglConfig(0),
+    mEglContext(0),
+    mEglSurface(0),
+    mGlesInitialized(false),
+    mIsOwnSurface(true),
+    mContextCurrent(false),
+    mIsWindow(true),
+    mColorDepth(COLOR_DEPTH_24),
+    mYInverted( -1 )
+{
+}
+
+EglImplementation::~EglImplementation()
+{
+  TerminateGles();
+}
+
+bool EglImplementation::InitializeGles( EGLNativeDisplayType display, bool isOwnSurface )
+{
+  if ( !mGlesInitialized )
+  {
+    mEglNativeDisplay = display;
+
+    //@todo see if we can just EGL_DEFAULT_DISPLAY instead
+    mEglDisplay = eglGetDisplay(mEglNativeDisplay);
+    EGLint error = eglGetError();
+
+    if( mEglDisplay == NULL && error != EGL_SUCCESS )
+    {
+      throw Dali::DaliException( "", "OpenGL ES is not supported");
+    }
+
+    EGLint majorVersion = 0;
+    EGLint minorVersion = 0;
+    if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
+    {
+      return false;
+    }
+    eglBindAPI(EGL_OPENGL_ES_API);
+
+    mContextAttribs.Clear();
+
+#if DALI_GLES_VERSION >= 30
+
+    mContextAttribs.Reserve(5);
+    mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
+    mContextAttribs.PushBack( 3 );
+    mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
+    mContextAttribs.PushBack( 0 );
+
+#else // DALI_GLES_VERSION >= 30
+
+    mContextAttribs.Reserve(3);
+    mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
+    mContextAttribs.PushBack( 2 );
+
+#endif // DALI_GLES_VERSION >= 30
+
+    mContextAttribs.PushBack( EGL_NONE );
+
+    mGlesInitialized = true;
+    mIsOwnSurface = isOwnSurface;
+  }
+
+  return mGlesInitialized;
+}
+
+bool EglImplementation::CreateContext()
+{
+  // make sure a context isn't created twice
+  DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
+
+  mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
+  TEST_EGL_ERROR("eglCreateContext render thread");
+
+  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
+
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
+
+  return true;
+}
+
+void EglImplementation::DestroyContext()
+{
+  DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
+
+  eglDestroyContext( mEglDisplay, mEglContext );
+  mEglContext = 0;
+}
+
+void EglImplementation::DestroySurface()
+{
+  if(mIsOwnSurface && mEglSurface)
+  {
+    eglDestroySurface( mEglDisplay, mEglSurface );
+    mEglSurface = 0;
+  }
+}
+
+void EglImplementation::MakeContextCurrent()
+{
+  mContextCurrent = true;
+
+  if(mIsOwnSurface)
+  {
+    eglMakeCurrent( mEglDisplay, mEglSurface, mEglSurface, mEglContext );
+  }
+
+  EGLint error = eglGetError();
+
+  if ( error != EGL_SUCCESS )
+  {
+    PrintEglError(error);
+
+    DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
+  }
+
+  // We want to display this information all the time, so use the LogMessage directly
+  Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
+      "            Vendor:        %s\n"
+      "            Version:       %s\n"
+      "            Client APIs:   %s\n"
+      "            Extensions:    %s\n",
+      eglQueryString(mEglDisplay, EGL_VENDOR),
+      eglQueryString(mEglDisplay, EGL_VERSION),
+      eglQueryString(mEglDisplay, EGL_CLIENT_APIS),
+      eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+}
+
+void EglImplementation::MakeContextNull()
+{
+  mContextCurrent = false;
+  // clear the current context
+  eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+}
+
+void EglImplementation::TerminateGles()
+{
+  if ( mGlesInitialized )
+  {
+    // in latest Mali DDK (r2p3 ~ r3p0 in April, 2012),
+    // MakeContextNull should be called before eglDestroy surface
+    // to prevent crash in _mali_surface_destroy_callback
+    MakeContextNull();
+
+    if(mIsOwnSurface && mEglSurface)
+    {
+      eglDestroySurface(mEglDisplay, mEglSurface);
+    }
+    eglDestroyContext(mEglDisplay, mEglContext);
+
+    eglTerminate(mEglDisplay);
+
+    mEglDisplay = NULL;
+    mEglConfig  = NULL;
+    mEglContext = NULL;
+    mEglSurface = NULL;
+
+    mGlesInitialized = false;
+  }
+}
+
+bool EglImplementation::IsGlesInitialized() const
+{
+  return mGlesInitialized;
+}
+
+void EglImplementation::SwapBuffers()
+{
+  eglSwapBuffers( mEglDisplay, mEglSurface );
+}
+
+void EglImplementation::CopyBuffers()
+{
+  eglCopyBuffers( mEglDisplay, mEglSurface, mEglNativePixmap );
+}
+
+void EglImplementation::WaitGL()
+{
+  eglWaitGL();
+}
+
+bool EglImplementation::IsPixmapYInverted()
+{
+  if( mYInverted == -1 )
+  {
+    const char* extension = eglQueryString( GetDisplay(), EGL_EXTENSIONS );
+
+    if( extension && strstr( extension, "EGL_NOK_texture_from_pixmap" ) )
+    {
+      eglGetConfigAttrib( GetDisplay(), GetConfig(), EGL_Y_INVERTED_NOK, &mYInverted );
+
+      DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "EGL_Y_INVERTED_NOK = %d\n", mYInverted );
+    }
+    else
+    {
+      mYInverted = 1;
+    }
+  }
+
+  return ( mYInverted == 1 ) ? true : false;
+}
+
+void EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
+{
+  if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
+  {
+    return;
+  }
+
+  mIsWindow = isWindowType;
+
+  EGLint numConfigs;
+  Vector<EGLint> configAttribs;
+  configAttribs.Reserve(31);
+
+  if(isWindowType)
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_WINDOW_BIT );
+  }
+  else
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_PIXMAP_BIT );
+  }
+
+  configAttribs.PushBack( EGL_RENDERABLE_TYPE );
+
+#if DALI_GLES_VERSION >= 30
+
+#ifdef _ARCH_ARM_
+  configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
+#else
+  // There is a bug in the desktop emulator
+  // Requesting for ES3 causes eglCreateContext even though it allows to ask
+  // for a configuration that supports GLES 3.0
+  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
+#endif // _ARCH_ARM_
+
+#else // DALI_GLES_VERSION >= 30
+
+  DALI_LOG_WARNING( "Using OpenGL ES 2 \n" );
+  configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
+
+#endif //DALI_GLES_VERSION >= 30
+
+#if DALI_GLES_VERSION >= 30
+// TODO: enable this flag when it becomes supported
+//  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
+//  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
+#endif //DALI_GLES_VERSION >= 30
+
+  configAttribs.PushBack( EGL_RED_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_GREEN_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_BLUE_SIZE );
+  configAttribs.PushBack( 8 );
+
+  configAttribs.PushBack( EGL_ALPHA_SIZE );
+#ifdef _ARCH_ARM_
+  configAttribs.PushBack( (depth == COLOR_DEPTH_32) ? 8 : 0 );
+#else
+  // There is a bug in the desktop emulator
+  // setting EGL_ALPHA_SIZE to 8 results in eglChooseConfig failing
+  configAttribs.PushBack( 0 );
+#endif // _ARCH_ARM_
+
+  configAttribs.PushBack( EGL_DEPTH_SIZE );
+  configAttribs.PushBack( 24 );
+  configAttribs.PushBack( EGL_STENCIL_SIZE );
+  configAttribs.PushBack( 8 );
+#ifndef DALI_PROFILE_UBUNTU
+  configAttribs.PushBack( EGL_SAMPLES );
+  configAttribs.PushBack( 4 );
+  configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
+  configAttribs.PushBack( 1 );
+#endif // DALI_PROFILE_UBUNTU
+  configAttribs.PushBack( EGL_NONE );
+
+  if ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE )
+  {
+    EGLint error = eglGetError();
+    switch (error)
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR("Display is not an EGL display connection\n");
+        break;
+      }
+      case EGL_BAD_ATTRIBUTE:
+      {
+        DALI_LOG_ERROR("The parameter configAttribs contains an invalid frame buffer configuration attribute or an attribute value that is unrecognized or out of range\n");
+        break;
+      }
+      case EGL_NOT_INITIALIZED:
+      {
+        DALI_LOG_ERROR("Display has not been initialized\n");
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR("The parameter numConfig is NULL\n");
+        break;
+      }
+      default:
+      {
+        DALI_LOG_ERROR("Unknown error.\n");
+      }
+    }
+    DALI_ASSERT_ALWAYS(false && "eglChooseConfig failed!");
+  }
+
+  if ( numConfigs != 1 )
+  {
+    DALI_LOG_ERROR("No configurations found.\n");
+
+    TEST_EGL_ERROR("eglChooseConfig");
+  }
+}
+
+void EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
+{
+  DALI_ASSERT_ALWAYS( ( mEglSurface == 0 ) && "EGL surface already exists" );
+
+  mEglNativeWindow = window;
+  mColorDepth = depth;
+  mIsWindow = true;
+
+  // egl choose config
+  ChooseConfig(mIsWindow, mColorDepth);
+
+  mEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
+  TEST_EGL_ERROR("eglCreateWindowSurface");
+
+  DALI_ASSERT_ALWAYS( mEglSurface && "Create window surface failed" );
+}
+
+void EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
+{
+  DALI_ASSERT_ALWAYS( mEglSurface == 0 && "Cannot create more than one instance of surface pixmap" );
+
+  mEglNativePixmap = pixmap;
+  mColorDepth = depth;
+  mIsWindow = false;
+
+  // egl choose config
+  ChooseConfig(mIsWindow, mColorDepth);
+
+  mEglSurface = eglCreatePixmapSurface( mEglDisplay, mEglConfig, mEglNativePixmap, NULL );
+  TEST_EGL_ERROR("eglCreatePixmapSurface");
+
+  DALI_ASSERT_ALWAYS( mEglSurface && "Create pixmap surface failed" );
+}
+
+bool EglImplementation::ReplaceSurfaceWindow( EGLNativeWindowType window )
+{
+  bool contextLost = false;
+
+  // display connection has not changed, then we can just create a new surface
+  //  the surface is bound to the context, so set the context to null
+  MakeContextNull();
+
+  // destroy the surface
+  DestroySurface();
+
+  // create the EGL surface
+  CreateSurfaceWindow( window, mColorDepth );
+
+  // set the context to be current with the new surface
+  MakeContextCurrent();
+
+  return contextLost;
+}
+
+bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap )
+{
+  bool contextLost = false;
+
+  //  the surface is bound to the context, so set the context to null
+  MakeContextNull();
+
+  // destroy the surface
+  DestroySurface();
+
+  // display connection has not changed, then we can just create a new surface
+  // create the EGL surface
+  CreateSurfacePixmap( pixmap, mColorDepth );
+
+  // set the context to be current with the new surface
+  MakeContextCurrent();
+
+  return contextLost;
+}
+
+EGLDisplay EglImplementation::GetDisplay() const
+{
+  return mEglDisplay;
+}
+
+EGLDisplay EglImplementation::GetContext() const
+{
+  return mEglContext;
+}
+
+EGLConfig EglImplementation::GetConfig() const
+{
+  return mEglConfig;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/file.list b/adaptors/x11/file.list
new file mode 100644 (file)
index 0000000..012a77f
--- /dev/null
@@ -0,0 +1,48 @@
+# x11
+
+_adaptor_x11_internal_src_files = \
+  $(adaptor_x11_dir)/clipboard-impl-x.cpp \
+  $(adaptor_x11_dir)/display-connection-impl-x.cpp \
+  $(adaptor_x11_dir)/imf-manager-impl-x.cpp \
+  $(adaptor_x11_dir)/native-image-source-impl-x.cpp \
+  $(adaptor_x11_dir)/server-connection-x.cpp \
+  $(adaptor_x11_dir)/virtual-keyboard-impl-x.cpp \
+  $(adaptor_x11_dir)/window-impl-x.cpp \
+  $(adaptor_x11_dir)/egl-implementation-x.cpp \
+  $(adaptor_x11_dir)/pixmap-render-surface-x.cpp \
+  $(adaptor_x11_dir)/ecore-x-render-surface.cpp \
+  $(adaptor_x11_dir)/window-render-surface-x.cpp \
+  $(adaptor_x11_dir)/ecore-x-window-interface.cpp
+
+adaptor_ecore_x_event_handler_internal_src_files = \
+  $(adaptor_x11_dir)/ecore-x-event-handler.cpp
+
+adaptor_uv_x_event_handler_internal_src_files = \
+  $(adaptor_x11_dir)/x-event-handler.cpp \
+  $(adaptor_x11_dir)/x-events/x-event-manager.cpp \
+  $(adaptor_x11_dir)/x-events/x-input2.cpp \
+  $(adaptor_x11_dir)/x-events/x-input2-device.cpp \
+  $(adaptor_x11_dir)/x-events/debug/x-input2-debug.cpp
+
+adaptor_x11_ubuntu_internal_src_files = \
+  $(_adaptor_x11_internal_src_files)
+
+adaptor_x11_tizen_internal_src_files = \
+  $(_adaptor_x11_internal_src_files) \
+  $(adaptor_x11_dir)/accessibility-adaptor-impl-x.cpp \
+  $(adaptor_x11_dir)/framework-x.cpp \
+  $(adaptor_x11_dir)/key-mapping-x.cpp \
+  $(adaptor_x11_dir)/window-extensions.cpp \
+  $(adaptor_x11_dir)/key-grab-x.cpp
+
+adaptor_x11_tv_internal_src_files = \
+  $(_adaptor_x11_internal_src_files) \
+  $(adaptor_x11_dir)/accessibility-adaptor-impl-x.cpp \
+  $(adaptor_x11_dir)/framework-x.cpp
+
+adaptor_x11_internal_default_profile_src_files = \
+  $(adaptor_x11_dir)/ecore-x-render-surface-factory.cpp \
+  $(adaptor_x11_dir)/system-settings-x.cpp
+
+devel_api_adaptor_tizen_x11_header_files = \
+  $(adaptor_x11_dir)/window-extensions.h
diff --git a/adaptors/x11/framework-x.cpp b/adaptors/x11/framework-x.cpp
new file mode 100644 (file)
index 0000000..c8a8455
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "framework.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xlib.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void Framework::InitThreads()
+{
+  XInitThreads();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/imf-manager-impl-x.cpp b/adaptors/x11/imf-manager-impl-x.cpp
new file mode 100644 (file)
index 0000000..f64fdd0
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <imf-manager-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <window-render-surface.h>
+#include <adaptor-impl.h>
+#include <singleton-service-impl.h>
+#include <virtual-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_IMF_MANAGER");
+#endif
+
+// Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
+size_t Utf8SequenceLength(const unsigned char leadByte)
+{
+  size_t length = 0;
+
+  if ((leadByte & 0x80) == 0 )          //ASCII character (lead bit zero)
+  {
+    length = 1;
+  }
+  else if (( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
+  {
+    length = 2;
+  }
+  else if (( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
+  {
+    length = 3;
+  }
+  else if (( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
+  {
+    length = 4;
+  }
+
+  return length;
+}
+
+// Static function calls used by ecore 'c' style callback registration
+void Commit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  if ( data )
+  {
+    ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
+    imfManager->CommitReceived( data, imfContext, event_info );
+  }
+}
+
+void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  if ( data )
+  {
+    ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
+    imfManager->PreEditChanged( data, imfContext, event_info );
+  }
+}
+
+Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
+{
+  if ( data )
+  {
+    ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
+    return imfManager->RetrieveSurrounding( data, imfContext, text, cursorPosition );
+  }
+  else
+  {
+    return false;
+  }
+}
+
+/**
+ * Called when an IMF delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  if ( data )
+  {
+    ImfManager* imfManager = reinterpret_cast< ImfManager* > ( data );
+    imfManager->DeleteSurrounding( data, imfContext, event_info );
+  }
+}
+
+BaseHandle Create()
+{
+  return ImfManager::Get();
+}
+
+TypeRegistration IMF_MANAGER_TYPE( typeid(Dali::ImfManager), typeid(Dali::BaseHandle), Create );
+
+} // unnamed namespace
+
+bool ImfManager::IsAvailable()
+{
+  bool available( false );
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    available = service.GetSingleton( typeid( Dali::ImfManager ) );
+  }
+
+  return available;
+}
+
+Dali::ImfManager ImfManager::Get()
+{
+  Dali::ImfManager manager;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ImfManager ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      manager = Dali::ImfManager( dynamic_cast< ImfManager* >( handle.GetObjectPtr() ) );
+    }
+    else if ( Adaptor::IsAvailable() )
+    {
+      // Create instance and register singleton only if the adaptor is available
+
+      Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
+      Any nativeWindow = adaptorImpl.GetNativeWindowHandle();
+
+      // The Ecore_X_Window needs to use the ImfManager.
+      // Only when the render surface is window, we can get the Ecore_X_Window.
+      Ecore_X_Window ecoreXwin( AnyCast<Ecore_X_Window>(nativeWindow) );
+      if (ecoreXwin)
+      {
+        // If we fail to get Ecore_X_Window, we can't use the ImfManager correctly.
+        // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
+        // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
+
+        manager = Dali::ImfManager( new ImfManager( ecoreXwin ) );
+        service.Register( typeid( manager ), manager );
+      }
+      else
+      {
+        DALI_LOG_ERROR("Failed to get native window handle");
+      }
+    }
+  }
+
+  return manager;
+}
+
+ImfManager::ImfManager( Ecore_X_Window ecoreXwin )
+: mIMFContext(),
+  mIMFCursorPosition( 0 ),
+  mSurroundingText(""),
+  mRestoreAfterFocusLost( false ),
+  mIdleCallbackConnected( false ),
+  mKeyEvents()
+{
+  ecore_imf_init();
+  CreateContext( ecoreXwin );
+
+  ConnectCallbacks();
+  VirtualKeyboard::ConnectCallbacks( mIMFContext );
+}
+
+ImfManager::~ImfManager()
+{
+  VirtualKeyboard::DisconnectCallbacks( mIMFContext );
+  DisconnectCallbacks();
+
+  DeleteContext();
+  ecore_imf_shutdown();
+}
+
+void ImfManager::CreateContext( Ecore_X_Window ecoreXwin )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CreateContext\n" );
+
+  const char *contextId = ecore_imf_context_default_id_get();
+  if( contextId )
+  {
+    mIMFContext = ecore_imf_context_add( contextId );
+
+    if( mIMFContext )
+    {
+      if( ecoreXwin )
+      {
+        ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( ecoreXwin ) );
+      }
+    }
+    else
+    {
+      DALI_LOG_WARNING("IMF Unable to get IMF Context\n");
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING("IMF Unable to get IMF Context\n");
+  }
+}
+
+void ImfManager::DeleteContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteContext\n" );
+
+  if ( mIMFContext )
+  {
+    mIMFContext = NULL;
+  }
+}
+
+// Callbacks for predicitive text support.
+void ImfManager::ConnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::ConnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
+
+    ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
+  }
+}
+
+void ImfManager::DisconnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DisconnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
+
+    // We do not need to unset the retrieve surrounding callback.
+  }
+}
+
+void ImfManager::Activate()
+{
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Activate\n" );
+
+    ecore_imf_context_focus_in( mIMFContext );
+
+    // emit keyboard activated signal
+    Dali::ImfManager handle( this );
+    mActivatedSignal.Emit( handle );
+  }
+}
+
+void ImfManager::Deactivate()
+{
+  if( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Deactivate\n" );
+
+    Reset();
+    ecore_imf_context_focus_out( mIMFContext );
+  }
+
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+}
+
+void ImfManager::Reset()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::Reset\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_reset( mIMFContext );
+  }
+}
+
+Ecore_IMF_Context* ImfManager::GetContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetContext\n" );
+
+  return mIMFContext;
+}
+
+bool ImfManager::RestoreAfterFocusLost() const
+{
+  return mRestoreAfterFocusLost;
+}
+
+void ImfManager::SetRestoreAfterFocusLost( bool toggle )
+{
+  mRestoreAfterFocusLost = toggle;
+}
+
+/**
+ * Called when an IMF Pre-Edit changed event is received.
+ * We are still predicting what the user is typing.  The latest string is what the IMF module thinks
+ * the user wants to type.
+ */
+void ImfManager::PreEditChanged( void *, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::PreEditChanged\n" );
+
+  char *preEditString( NULL );
+  int cursorPosition( 0 );
+  Eina_List *attrs = NULL;
+  Eina_List *l = NULL;
+
+  Ecore_IMF_Preedit_Attr *attr;
+
+  // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
+  // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
+  ecore_imf_context_preedit_string_with_attributes_get( imfContext, &preEditString, &attrs, &cursorPosition );
+
+  if ( attrs )
+  {
+    // iterate through the list of attributes getting the type, start and end position.
+    for ( l = attrs, (attr =  (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ); l; l = eina_list_next(l), ( attr = (Ecore_IMF_Preedit_Attr*)eina_list_data_get(l) ))
+    {
+#ifdef DALI_PROFILE_UBUNTU
+      if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB3 ) // (Ecore_IMF)
+#else // DALI_PROFILE_UBUNTU
+      if ( attr->preedit_type == ECORE_IMF_PREEDIT_TYPE_SUB4 ) // (Ecore_IMF)
+#endif // DALI_PROFILE_UBUNTU
+      {
+        // check first byte so know how many bytes a character is represented by as keyboard returns cursor position in bytes. Which is different for some languages.
+
+        size_t visualCharacterIndex = 0;
+        size_t byteIndex = 0;
+
+        // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
+        while ( preEditString[byteIndex] != '\0' )
+        {
+          // attr->end_index is provided as a byte position not character and we need to know the character position.
+          size_t currentSequenceLength = Utf8SequenceLength(preEditString[byteIndex]); // returns number of bytes used to represent character.
+          if ( byteIndex == attr->end_index )
+          {
+            cursorPosition = visualCharacterIndex;
+            break;
+            // end loop as found cursor position that matches byte position
+          }
+          else
+          {
+            byteIndex += currentSequenceLength; // jump to next character
+            visualCharacterIndex++;  // increment character count so we know our position for when we get a match
+          }
+
+          DALI_ASSERT_DEBUG( visualCharacterIndex < strlen( preEditString ));
+        }
+      }
+    }
+  }
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    std::string keyString ( preEditString );
+    int numberOfChars( 0 );
+
+    Dali::ImfManager handle( this );
+    Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::PREEDIT, keyString, cursorPosition, numberOfChars );
+    Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
+
+    if ( callbackData.update )
+    {
+      SetCursorPosition( callbackData.cursorPosition );
+      SetSurroundingText( callbackData.currentText );
+
+      NotifyCursorPosition();
+    }
+
+    if ( callbackData.preeditResetRequired )
+    {
+      Reset();
+    }
+  }
+  free( preEditString );
+}
+
+void ImfManager::CommitReceived( void *, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::CommitReceived\n" );
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    const std::string keyString( (char *)event_info );
+    const int cursorOffset( 0 );
+    const int numberOfChars( 0 );
+
+    Dali::ImfManager handle( this );
+    Dali::ImfManager::ImfEventData imfEventData ( Dali::ImfManager::COMMIT, keyString, cursorOffset, numberOfChars );
+    Dali::ImfManager::ImfCallbackData callbackData = mEventSignal.Emit( handle, imfEventData );
+
+    if ( callbackData.update )
+    {
+      SetCursorPosition( callbackData.cursorPosition );
+      SetSurroundingText( callbackData.currentText );
+
+      NotifyCursorPosition();
+    }
+  }
+}
+
+/**
+ * Called when an IMF retrieve surround event is received.
+ * Here the IMF module wishes to know the string we are working with and where within the string the cursor is
+ * We need to signal the application to tell us this information.
+ */
+Eina_Bool ImfManager::RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::RetrieveSurrounding\n" );
+
+  std::string keyString ( "" );
+  int cursorOffset( 0 );
+  int numberOfChars( 0 );
+
+  Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::GETSURROUNDING , keyString, cursorOffset, numberOfChars );
+  Dali::ImfManager handle( this );
+  mEventSignal.Emit( handle, imfData );
+
+  if ( text )
+  {
+    std::string surroundingText( GetSurroundingText() );
+
+    if ( !surroundingText.empty() )
+    {
+      *text = strdup( surroundingText.c_str() );
+    }
+    else
+    {
+      *text = strdup( "" );
+    }
+  }
+
+  if ( cursorPosition )
+  {
+    *cursorPosition = GetCursorPosition();
+  }
+
+
+  return EINA_TRUE;
+}
+
+/**
+ * Called when an IMF delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void ImfManager::DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::DeleteSurrounding\n" );
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = (Ecore_IMF_Event_Delete_Surrounding*) event_info;
+
+    const std::string keyString( "" );
+    const int cursorOffset( deleteSurroundingEvent->offset );
+    const int numberOfChars( deleteSurroundingEvent->n_chars );
+
+    Dali::ImfManager::ImfEventData imfData ( Dali::ImfManager::DELETESURROUNDING , keyString, cursorOffset, numberOfChars );
+    Dali::ImfManager handle( this );
+    mEventSignal.Emit( handle, imfData );
+  }
+}
+
+void ImfManager::NotifyCursorPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::NotifyCursorPosition\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
+  }
+}
+
+int ImfManager::GetCursorPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetCursorPosition\n" );
+
+  return mIMFCursorPosition;
+}
+
+void ImfManager::SetCursorPosition( unsigned int cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetCursorPosition\n" );
+
+  mIMFCursorPosition = ( int )cursorPosition;
+}
+
+void ImfManager::SetSurroundingText( std::string text )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::SetSurroundingText\n" );
+
+  mSurroundingText = text;
+}
+
+std::string ImfManager::GetSurroundingText()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "ImfManager::GetSurroundingText\n" );
+
+  return mSurroundingText;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/adaptors/x11/imf-manager-impl.h b/adaptors/x11/imf-manager-impl.h
new file mode 100644 (file)
index 0000000..0ae0f9f
--- /dev/null
@@ -0,0 +1,236 @@
+#ifndef __DALI_INTERNAL_IMF_MANAGER_H
+#define __DALI_INTERNAL_IMF_MANAGER_H
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_IMF.h>
+#include <Ecore_X.h>
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/events/key-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <imf-manager.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class ImfManager : public Dali::BaseObject
+{
+public:
+  typedef Dali::ImfManager::ImfManagerSignalType ImfManagerSignalType;
+  typedef Dali::ImfManager::ImfEventSignalType ImfEventSignalType;
+
+public:
+
+  /**
+   * Check whether the ImfManager is available.
+   * @return true if available, false otherwise
+   */
+  static bool IsAvailable();
+
+  /**
+   * Get the IMF manager instance, it creates the instance if it has not already been created.
+   * Internally, a check should be made using IsAvailable() before this is called as we do not want
+   * to create an instance if not needed by applications.
+   * @see IsAvailable()
+   */
+  static Dali::ImfManager Get();
+
+  /**
+   * Constructor
+   * @param[in] ecoreXwin, The window is created by application.
+   */
+  ImfManager( Ecore_X_Window ecoreXwin );
+
+  /**
+   * Connect Callbacks required for IMF.
+   * If you don't connect imf callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit and DeleteSurrounding.
+   */
+  void ConnectCallbacks();
+
+  /**
+   * Disconnect Callbacks attached to imf context.
+   */
+  void DisconnectCallbacks();
+
+  /**
+   * @copydoc Dali::ImfManager::Activate()
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::ImfManager::Deactivate()
+   */
+  void Deactivate();
+
+  /**
+   * @copydoc Dali::ImfManager::Reset()
+   */
+  void Reset();
+
+  /**
+   * @copydoc Dali::ImfManager::GetContext()
+   */
+  Ecore_IMF_Context* GetContext();
+
+  /**
+   * @copydoc Dali::ImfManager::RestoreAfterFocusLost()
+   */
+  bool RestoreAfterFocusLost() const;
+
+  /**
+   * @copydoc Dali::ImfManager::SetRestoreAfterFocusLost()
+   */
+  void SetRestoreAfterFocusLost( bool toggle );
+
+  /**
+   * @copydoc Dali::ImfManager::PreEditChanged()
+   */
+  void PreEditChanged( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  void CommitReceived( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  Eina_Bool RetrieveSurrounding( void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition );
+
+  /**
+   * @copydoc Dali::ImfManager::DeleteSurrounding()
+   */
+  void DeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *event_info );
+
+  // Cursor related
+  /**
+   * @copydoc Dali::ImfManager::NotifyCursorPosition()
+   */
+  void NotifyCursorPosition();
+
+  /**
+   * @copydoc Dali::ImfManager::GetCursorPosition()
+   */
+  int GetCursorPosition();
+
+  /**
+   * @copydoc Dali::ImfManager::SetCursorPosition()
+   */
+  void SetCursorPosition( unsigned int cursorPosition );
+
+  /**
+   * @copydoc Dali::ImfManager::SetSurroundingText()
+   */
+  void SetSurroundingText( std::string text );
+
+  /**
+   * @copydoc Dali::ImfManager::GetSurroundingText()
+   */
+  std::string GetSurroundingText();
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::ImfManager::ActivatedSignal()
+   */
+  ImfManagerSignalType& ActivatedSignal() { return mActivatedSignal; }
+
+  /**
+   * @copydoc Dali::ImfManager::EventReceivedSignal()
+   */
+  ImfEventSignalType& EventReceivedSignal() { return mEventSignal; }
+
+protected:
+
+  /**
+   * Destructor.
+   */
+  virtual ~ImfManager();
+
+private:
+  /**
+   * Context created the first time and kept until deleted.
+   * @param[in] ecoreXwin, The window is created by application.
+   */
+  void CreateContext( Ecore_X_Window ecoreXwin );
+
+  /**
+   * @copydoc Dali::ImfManager::DeleteContext()
+   */
+  void DeleteContext();
+
+private:
+  // Undefined
+  ImfManager( const ImfManager& );
+  ImfManager& operator=( ImfManager& );
+
+private:
+  Ecore_IMF_Context* mIMFContext;
+  int mIMFCursorPosition;
+  std::string mSurroundingText;
+
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
+
+  std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
+
+  ImfManagerSignalType      mActivatedSignal;
+  ImfEventSignalType        mEventSignal;
+
+public:
+
+inline static Internal::Adaptor::ImfManager& GetImplementation(Dali::ImfManager& imfManager)
+{
+  DALI_ASSERT_ALWAYS( imfManager && "ImfManager handle is empty" );
+
+  BaseObject& handle = imfManager.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::ImfManager&>(handle);
+}
+
+inline static const  Internal::Adaptor::ImfManager& GetImplementation(const Dali::ImfManager& imfManager)
+{
+  DALI_ASSERT_ALWAYS( imfManager && "ImfManager handle is empty" );
+
+  const BaseObject& handle = imfManager.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::ImfManager&>(handle);
+}
+
+};
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_IMF_MANAGER_H
diff --git a/adaptors/x11/key-grab-x.cpp b/adaptors/x11/key-grab-x.cpp
new file mode 100644 (file)
index 0000000..652a31d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <key-grab.h>
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+#include <Ecore_X.h>
+#include <utilX.h>
+
+// INTERNAL INCLUDES
+#include <window.h>
+#include <key-impl.h>
+#include <ecore-x-types.h>
+
+namespace Dali
+{
+
+namespace KeyGrab
+{
+
+bool GrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  return GrabKey( window, daliKey, TOPMOST);
+}
+
+bool UngrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  return UngrabKey( window, daliKey );
+}
+
+bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode )
+{
+  int xGrabMode;
+  if( grabMode == TOPMOST )
+  {
+    xGrabMode = TOP_POSITION_GRAB;
+  }
+  else if( grabMode == SHARED )
+  {
+    xGrabMode = SHARED_GRAB;
+  }
+  else if( grabMode == OVERRIDE_EXCLUSIVE )
+  {
+    xGrabMode = OR_EXCLUSIVE_GRAB;
+  }
+  else if( grabMode == EXCLUSIVE )
+  {
+    xGrabMode = EXCLUSIVE_GRAB;
+  }
+  else
+  {
+    return false;
+  }
+
+  int ret = -1;
+  const char* key = Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey );
+
+  if( key != NULL )
+  {
+    ret = utilx_grab_key ( static_cast<Display*>( ecore_x_display_get() ),
+                             static_cast<XWindow>( AnyCast<Ecore_X_Window>( window.GetNativeHandle() ) ),
+                             key, xGrabMode );
+  }
+  return ret==0;
+}
+
+bool UngrabKey( Window window, Dali::KEY daliKey )
+{
+  int ret = -1;
+  const char* key = Dali::Internal::Adaptor::KeyLookup::GetKeyName( daliKey );
+
+  if( key != NULL )
+  {
+    ret = utilx_ungrab_key ( static_cast<Display*>( ecore_x_display_get() ),
+                               static_cast<XWindow>( AnyCast<Ecore_X_Window>( window.GetNativeHandle() ) ),
+                               key );
+  }
+  return ret==0;
+}
+
+} // namespace KeyGrab
+
+} // namespace Dali
+
+
diff --git a/adaptors/x11/key-mapping-x.cpp b/adaptors/x11/key-mapping-x.cpp
new file mode 100644 (file)
index 0000000..912ea8a
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "key-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,          false },
+  { "Menu",                  DALI_KEY_MENU,            false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,      false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,     false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable))/ (sizeof(KeyLookup));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/native-image-source-impl-x.cpp b/adaptors/x11/native-image-source-impl-x.cpp
new file mode 100644 (file)
index 0000000..136f58e
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "native-image-source-impl.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore_X.h>
+#include <X11/Xutil.h>
+#include <X11/Xlib.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <gl/egl-image-extensions.h>
+#include <gl/egl-implementation.h>
+#include <gl/egl-factory.h>
+#include <adaptor-impl.h>
+#include <bitmap-saver.h>
+#include <render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+using Dali::Integration::PixelBuffer;
+
+// Pieces needed to save compressed images (temporary location while plumbing):
+namespace
+{
+
+  /**
+   * Free an allocated XImage on destruction.
+   */
+  struct XImageJanitor
+  {
+    XImageJanitor( XImage* const  pXImage ) : mXImage( pXImage )
+    {
+      DALI_ASSERT_DEBUG(pXImage != 0 && "Null pointer to XImage.");
+    }
+
+    ~XImageJanitor()
+    {
+      if( mXImage )
+      {
+        if( !XDestroyImage(mXImage) )
+        {
+          DALI_ASSERT_DEBUG("XImage deallocation failure");
+        }
+      }
+    }
+    XImage* const  mXImage;
+  private:
+    XImageJanitor( const XImageJanitor& rhs );
+    XImageJanitor& operator = ( const XImageJanitor& rhs );
+  };
+}
+
+NativeImageSource* NativeImageSource::New(unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSource* image = new NativeImageSource( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  // 2nd phase construction
+  if(image) //< Defensive in case we ever compile without exceptions.
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnPixmap( true ),
+  mPixmap( 0 ),
+  mBlendingRequired( false ),
+  mYInverted( true ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglImageExtensions( NULL )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+  EglFactory& eglFactory = Adaptor::GetImplementation( Adaptor::Get() ).GetEGLFactory();
+  mEglImageExtensions = eglFactory.GetImageExtensions();
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  // assign the pixmap
+  mPixmap = GetPixmapFromAny(nativeImageSource);
+
+  mYInverted = eglFactory.GetImplementation()->IsPixmapYInverted();
+}
+
+void NativeImageSource::Initialize()
+{
+  // if pixmap has been created outside of X11 Image we can return
+  if (mPixmap)
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+    return;
+  }
+
+  // get the pixel depth
+  int depth = GetPixelDepth(mColorDepth);
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+
+  mPixmap = ecore_x_pixmap_new( 0, mWidth, mHeight, depth );
+  ecore_x_sync();
+}
+
+NativeImageSource::~NativeImageSource()
+{
+  if (mOwnPixmap && mPixmap)
+  {
+    ecore_x_pixmap_free(mPixmap);
+  }
+}
+
+Any NativeImageSource::GetNativeImageSource() const
+{
+  // return ecore x11 type
+  return Any(mPixmap);
+}
+
+bool NativeImageSource::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+  DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
+  bool success = false;
+  width  = mWidth;
+  height = mHeight;
+
+  // Open a display connection
+  Display* displayConnection = XOpenDisplay( 0 );
+
+  XImageJanitor xImageJanitor( XGetImage( displayConnection,
+                                          mPixmap,
+                                          0, 0, // x,y of subregion to extract.
+                                          width, height, // of suregion to extract.
+                                          0xFFFFFFFF,
+                                          ZPixmap ) );
+  XImage* const  pXImage = xImageJanitor.mXImage;
+  DALI_ASSERT_DEBUG(pXImage && "XImage (from pixmap) could not be retrieved from the server");
+  if(!pXImage)
+  {
+    DALI_LOG_ERROR("Could not retrieve Ximage.");
+  }
+  else
+  {
+    switch(pXImage->depth)
+    {
+      // Note, depth is a logical value. On target the framebuffer is still 32bpp
+      // (see pXImage->bits_per_pixel) so we go through XGetPixel() and swizzle.
+      // Note, this could be the default, fallback case for all depths if *pXImage
+      // didn't have blank RGB masks (X bug), but we have to hardcode the masks and
+      // shifts instead.
+      case 24:
+      {
+        pixelFormat = Pixel::RGB888;
+        pixbuf.resize(width*height*3);
+        unsigned char* bufPtr = &pixbuf[0];
+
+        if( mYInverted )
+        {
+          for( unsigned y = height-1; y < height; --y )
+          {
+            for( unsigned x = 0; x < width; ++x, bufPtr+=3 )
+            {
+              const unsigned pixel = XGetPixel(pXImage,x,y);
+
+              // store as RGB
+              const unsigned blue  =  pixel & 0xFFU;
+              const unsigned green = (pixel >> 8)  & 0xFFU;
+              const unsigned red   = (pixel >> 16) & 0xFFU;
+
+              *bufPtr = red;
+              *(bufPtr+1) = green;
+              *(bufPtr+2) = blue;
+            }
+          }
+        }
+        else
+        {
+          for( unsigned y = 0; y < height; ++y )
+          {
+            for( unsigned x = 0; x < width; ++x, bufPtr+=3 )
+            {
+              const unsigned pixel = XGetPixel(pXImage,x,y);
+
+              // store as RGB
+              const unsigned blue  =  pixel & 0xFFU;
+              const unsigned green = (pixel >> 8)  & 0xFFU;
+              const unsigned red   = (pixel >> 16) & 0xFFU;
+
+              *bufPtr = red;
+              *(bufPtr+1) = green;
+              *(bufPtr+2) = blue;
+            }
+          }
+        }
+        success = true;
+        break;
+      }
+      case 32:
+      {
+        if(pXImage->data)
+        {
+          // Sweep through the image, doing a vertical flip, but handling each scanline as
+          // an inlined intrinsic/builtin memcpy (should be fast):
+          pixbuf.resize(width*height*4);
+          unsigned * bufPtr = reinterpret_cast<unsigned *>(&pixbuf[0]);
+          const unsigned xDataLineSkip = pXImage->bytes_per_line;
+          const size_t copy_count = width * 4;
+          pixelFormat = Pixel::BGRA8888;
+
+          if( mYInverted )
+          {
+            for( unsigned y = height - 1; y < height; --y, bufPtr += width )
+            {
+              const char * const in = pXImage->data + xDataLineSkip * y;
+
+              // Copy a whole scanline at a time:
+              DALI_ASSERT_DEBUG( size_t( bufPtr ) >= size_t( &pixbuf[0] ));
+              DALI_ASSERT_DEBUG( reinterpret_cast<size_t>( bufPtr ) + copy_count <= reinterpret_cast<size_t>( &pixbuf[pixbuf.size()] ) );
+              DALI_ASSERT_DEBUG( in >= pXImage->data );
+              DALI_ASSERT_DEBUG( in + copy_count <= pXImage->data + xDataLineSkip * height );
+              __builtin_memcpy( bufPtr, in, copy_count );
+            }
+          }
+          else
+          {
+            for ( unsigned y = 0; y < height; ++y, bufPtr += width )
+            {
+              const char * const in = pXImage->data + xDataLineSkip * y;
+
+              // Copy a whole scanline at a time:
+              DALI_ASSERT_DEBUG( size_t( bufPtr ) >= size_t( &pixbuf[0] ));
+              DALI_ASSERT_DEBUG( reinterpret_cast<size_t>( bufPtr ) + copy_count <= reinterpret_cast<size_t>( &pixbuf[pixbuf.size()] ) );
+              DALI_ASSERT_DEBUG( in >= pXImage->data );
+              DALI_ASSERT_DEBUG( in + copy_count <= pXImage->data + xDataLineSkip * height );
+              __builtin_memcpy( bufPtr, in, copy_count );
+            }
+          }
+          success = true;
+        }
+        else
+        {
+          DALI_LOG_ERROR("XImage has null data pointer.");
+        }
+        break;
+      }
+      // Make a case for 16 bit modes especially to remember that the only reason we don't support them is a bug in X:
+      case 16:
+      {
+        DALI_ASSERT_DEBUG(pXImage->red_mask && pXImage->green_mask && pXImage->blue_mask && "No image masks mean 16 bit modes are not possible.");
+        ///! If the above assert doesn't fail in a debug build, the X bug may have been fixed, so revisit this function.
+        ///! No break, fall through to the general unsupported format warning below.
+      }
+      default:
+      {
+        DALI_LOG_WARNING("Pixmap has unsupported bit-depth for getting pixels: %u", pXImage->depth);
+      }
+    }
+  }
+  if(!success)
+  {
+    DALI_LOG_ERROR("Failed to get pixels from NativeImageSource.");
+    pixbuf.resize(0);
+    width = 0;
+    height = 0;
+  }
+
+  // Close the display connection
+  XCloseDisplay( displayConnection );
+
+  return success;
+}
+
+bool NativeImageSource::EncodeToFile(const std::string& filename) const
+{
+  std::vector< unsigned char > pixbuf;
+  unsigned int width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if(GetPixels(pixbuf, width, height, pixelFormat))
+  {
+    return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
+  }
+  return false;
+}
+
+bool NativeImageSource::GlExtensionCreate()
+{
+  // if the image existed previously delete it.
+  if (mEglImageKHR != NULL)
+  {
+    GlExtensionDestroy();
+  }
+
+  // casting from an unsigned int to a void *, which should then be cast back
+  // to an unsigned int in the driver.
+  EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
+
+  mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
+
+  return mEglImageKHR != NULL;
+}
+
+void NativeImageSource::GlExtensionDestroy()
+{
+  mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
+
+  mEglImageKHR = NULL;
+}
+
+unsigned int NativeImageSource::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
+
+  return 0;
+}
+
+int NativeImageSource::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
+{
+  switch (depth)
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+    {
+      // Get the default screen depth
+      return ecore_x_default_depth_get(ecore_x_display_get(), ecore_x_default_screen_get());
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8:
+    {
+      return 8;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_16:
+    {
+      return 16;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_24:
+    {
+      return 24;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_32:
+    {
+      return 32;
+    }
+    default:
+    {
+      DALI_ASSERT_DEBUG(0 && "unknown color enum");
+      return 0;
+    }
+  }
+}
+
+Ecore_X_Pixmap NativeImageSource::GetPixmapFromAny(Any pixmap) const
+{
+  if (pixmap.Empty())
+  {
+    return 0;
+  }
+
+  // see if it is of type x11 pixmap
+  if (pixmap.GetType() == typeid (Pixmap))
+  {
+    // get the x pixmap type
+    Pixmap xpixmap = AnyCast<Pixmap>(pixmap);
+
+    // cast it to a ecore pixmap type
+    return static_cast<Ecore_X_Pixmap>(xpixmap);
+  }
+  else
+  {
+    return AnyCast<Ecore_X_Pixmap>(pixmap);
+  }
+}
+
+void NativeImageSource::GetPixmapDetails()
+{
+  int x, y;
+
+  // get the width, height and depth
+  ecore_x_pixmap_geometry_get(mPixmap, &x, &y, (int*)&mWidth, (int*)&mHeight);
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  int depth = ecore_x_pixmap_depth_get(mPixmap);
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/adaptors/x11/native-image-source-impl.h b/adaptors/x11/native-image-source-impl.h
new file mode 100644 (file)
index 0000000..a1682e8
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
+#define __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <Ecore_X.h>
+
+// INTERNAL INCLUDES
+#include <native-image-source.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] depth color depth of the image
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSource* New( unsigned int width,
+                          unsigned int height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource );
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSource();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  unsigned int GetWidth() const
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  unsigned int GetHeight() const
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const
+  {
+    return mBlendingRequired;
+  }
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  NativeImageSource( unsigned int width,
+              unsigned  int height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource );
+
+  /**
+   * 2nd phase construction.
+   */
+  void Initialize();
+
+  /**
+   * Uses X11 to get the default depth.
+   * @param depth the PixelImage depth enum
+   * @return default x11 pixel depth
+   */
+  int GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const;
+
+  /**
+   * Gets the pixmap from the Any parameter
+   * @param pixmap contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   * @return pixmap x11 pixmap
+   */
+  Ecore_X_Pixmap GetPixmapFromAny(Any pixmap) const;
+
+  /**
+   * Given an existing pixmap, the function uses X to find out
+   * the width, heigth and depth of that pixmap.
+   */
+  void GetPixmapDetails();
+
+private:
+
+  unsigned int mWidth;                        ///< pixmap width
+  unsigned int mHeight;                       ///< pixmap heights
+  bool mOwnPixmap;                            ///< Whether we created pixmap or not
+  Ecore_X_Pixmap mPixmap;                     ///< From Xlib
+  bool mBlendingRequired;                     ///< Whether blending is required
+  bool mYInverted;                            ///< Whether pixmap is y-inverted
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of pixmap
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H__
diff --git a/adaptors/x11/pixmap-render-surface-x.cpp b/adaptors/x11/pixmap-render-surface-x.cpp
new file mode 100644 (file)
index 0000000..7f32b6e
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "pixmap-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <X11/extensions/Xfixes.h> // for damage notify
+#include <X11/extensions/Xdamage.h> // for damage notify
+
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/mutex.h>
+
+// INTERNAL INCLUDES
+
+#include <integration-api/thread-synchronization-interface.h>
+#include <ecore-x-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+#include <base/display-connection.h>
+#include <base/conditional-wait.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gRenderSurfaceLogFilter;
+#endif
+
+namespace ECore
+{
+
+struct PixmapRenderSurface::Impl
+{
+  Ecore_X_Pixmap                  mX11Pixmap;             ///< X-Pixmap
+  ThreadSynchronizationInterface* mThreadSynchronization; ///< A pointer to the thread-synchronization
+};
+
+PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
+                                         Any surface,
+                                         const std::string& name,
+                                         bool isTransparent)
+: EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
+  mImpl( new Impl )
+{
+  mImpl->mThreadSynchronization = NULL;
+  Init( surface );
+}
+
+PixmapRenderSurface::~PixmapRenderSurface()
+{
+  // release the surface if we own one
+  if( mOwnSurface )
+  {
+    // if we did create the pixmap, delete the pixmap
+    DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", mImpl->mX11Pixmap );
+    ecore_x_pixmap_free( mImpl->mX11Pixmap );
+  }
+
+  delete mImpl;
+}
+
+Ecore_X_Drawable PixmapRenderSurface::GetDrawable()
+{
+  return (Ecore_X_Drawable) mImpl->mX11Pixmap;
+}
+
+Any PixmapRenderSurface::GetSurface()
+{
+  return Any( mImpl->mX11Pixmap );
+}
+
+void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+
+  eglImpl.ChooseConfig(false, mColorDepth);
+}
+
+void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+
+  // create the EGL surface
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
+  eglImpl.CreateSurfacePixmap( (EGLNativePixmapType)pixmap, mColorDepth ); // reinterpret_cast does not compile
+}
+
+void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+  eglImpl.DestroySurface();
+}
+
+bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  // a new surface for the new pixmap
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+
+  return eglImpl.ReplaceSurfacePixmap( (EGLNativePixmapType)pixmap ); // reinterpret_cast does not compile
+
+}
+
+void PixmapRenderSurface::StartRender()
+{
+}
+
+bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
+{
+  // nothing to do for pixmaps
+  return true;
+}
+
+void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
+{
+  // flush gl instruction queue
+  glAbstraction.Flush();
+
+  if( mImpl->mThreadSynchronization )
+  {
+    mImpl->mThreadSynchronization->PostRenderStarted();
+  }
+
+  // create damage for client applications which wish to know the update timing
+  if( mRenderNotification )
+  {
+    // use notification trigger
+    // Tell the event-thread to render the pixmap
+    mRenderNotification->Trigger();
+  }
+  else
+  {
+    // as a fallback, send damage event.
+    Ecore_X_Drawable drawable = GetDrawable();
+
+    if( drawable )
+    {
+      XRectangle rect;
+      XserverRegion region;
+
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = mPosition.width;
+      rect.height = mPosition.height;
+
+      XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
+
+      // make a fixes region as updated area
+      region = XFixesCreateRegion( display, &rect, 1 );
+      // add damage event to updated drawable
+      XDamageAdd( display, (Drawable)drawable, region );
+      XFixesDestroyRegion( display, region );
+
+      XFlush( display );
+    }
+  }
+
+  if( mImpl->mThreadSynchronization )
+  {
+    mImpl->mThreadSynchronization->PostRenderWaitForCompletion();
+  }
+}
+
+void PixmapRenderSurface::StopRender()
+{
+  ReleaseLock();
+}
+
+void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+  mImpl->mThreadSynchronization = &threadSynchronization;
+}
+
+void PixmapRenderSurface::CreateXRenderable()
+{
+  // check we're creating one with a valid size
+  DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
+
+  // create the pixmap
+  mImpl->mX11Pixmap = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
+
+  // clear the pixmap
+  unsigned int foreground;
+  Ecore_X_GC gc;
+  foreground = 0;
+  gc = ecore_x_gc_new( mImpl->mX11Pixmap,
+                       ECORE_X_GC_VALUE_MASK_FOREGROUND,
+                       &foreground );
+
+  DALI_ASSERT_ALWAYS( gc && "CreateXRenderable(): failed to get gc" );
+
+  ecore_x_drawable_rectangle_fill( mImpl->mX11Pixmap, gc, 0, 0, mPosition.width, mPosition.height );
+
+  DALI_ASSERT_ALWAYS( mImpl->mX11Pixmap && "Failed to create X pixmap" );
+
+  // we SHOULD guarantee the xpixmap/x11 window was created in x server.
+  ecore_x_sync();
+
+  ecore_x_gc_free(gc);
+}
+
+void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
+{
+  mImpl->mX11Pixmap = static_cast< Ecore_X_Pixmap >( surfaceId );
+}
+
+void PixmapRenderSurface::ReleaseLock()
+{
+  if( mImpl->mThreadSynchronization )
+  {
+    mImpl->mThreadSynchronization->PostRenderComplete();
+  }
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/x11/server-connection-x.cpp b/adaptors/x11/server-connection-x.cpp
new file mode 100644 (file)
index 0000000..4b0b3c3
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "server-connection.h"
+
+// EXTERNAL INCLUDES
+#include <Ecore.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gIndicatorLogFilter;
+#endif
+
+
+ServerConnection::ServerConnection(
+  const char*                 serviceName,
+  int                         serviceNumber,
+  bool                        isSystem,
+  ServerConnection::Observer* observer)
+
+: mConnected(false),
+  mObserver(observer)
+{
+  Ecore_Ipc_Type ipctype = ECORE_IPC_LOCAL_USER;
+
+  ecore_ipc_init();
+  mService.name = eina_stringshare_add(serviceName);
+  mService.num = serviceNumber;
+  mService.isSystem = isSystem;
+
+  if (mService.isSystem)
+  {
+    ipctype = ECORE_IPC_LOCAL_SYSTEM;
+  }
+
+  DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "ServerConnection: Connecting to %s %d\n", mService.name, mService.num );
+
+  mIpcServer = ecore_ipc_server_connect( ipctype, (char *)mService.name, mService.num, this );
+
+  if( !mIpcServer )
+  {
+    DALI_LOG_INFO( gIndicatorLogFilter, Debug::General, "mIpcServer is null\n" );
+    ecore_ipc_shutdown();
+  }
+  else
+  {
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_ADD,
+                                                     &ServerConnection::IpcServerAdd,
+                                                     this ) );
+
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_DEL,
+                                                     &ServerConnection::IpcServerDel,
+                                                     this ) );
+
+    mIpcHandlers.push_back( ecore_event_handler_add( ECORE_IPC_EVENT_SERVER_DATA,
+                                                     &ServerConnection::IpcServerData,
+                                                     this));
+
+    mConnected = true;
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/x11/system-settings-x.cpp b/adaptors/x11/system-settings-x.cpp
new file mode 100644 (file)
index 0000000..124e38a
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#ifndef DALI_PROFILE_UBUNTU
+#include <system_settings.h>
+#endif // DALI_PROFILE_UBUNTU
+#include <Elementary.h>
+
+// INTERNAL INCLUDES
+#include "system-settings.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetElmAccessActionOver()
+{
+#ifndef DALI_PROFILE_UBUNTU
+  // ELM_ACCESS_ACTION_OVER not available in common profile
+  return ELM_ACCESS_ACTION_LAST;
+#else // DALI_PROFILE_UBUNTU
+  return 0;
+#endif // DALI_PROFILE_UBUNTU
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/virtual-keyboard-impl-x.cpp b/adaptors/x11/virtual-keyboard-impl-x.cpp
new file mode 100644 (file)
index 0000000..b1fdc60
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "virtual-keyboard-impl.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xlib.h>
+#include <Ecore_X.h>
+#include <algorithm>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <adaptor.h>
+#include <locale-utils.h>
+#include <imf-manager-impl.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+Dali::InputMethod::ActionButton gActionButtonFunction = Dali::InputMethod::ACTION_DEFAULT;
+
+Ecore_IMF_Input_Panel_Return_Key_Type actionButtonMapping(Dali::InputMethod::ActionButton actionButton )
+{
+  switch( actionButton )
+  {
+    case InputMethod::ACTION_DEFAULT:     return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ACTION_DONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE;
+    case InputMethod::ACTION_GO:          return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO;
+    case InputMethod::ACTION_JOIN:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN;
+    case InputMethod::ACTION_LOGIN:       return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN;
+    case InputMethod::ACTION_NEXT:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT;
+    case InputMethod::ACTION_PREVIOUS:    return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ACTION_SEARCH:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
+    case InputMethod::ACTION_SEND:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND;
+    case InputMethod::ACTION_SIGNIN:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ACTION_UNSPECIFIED: return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ACTION_NONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    default:                              return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+  }
+}
+
+void RotateTo(int angle)
+{
+  // Get focus window used by Keyboard and rotate it
+  Display* display = XOpenDisplay(0);
+  if (display)
+  {
+    ::Window focusWindow;
+    int revert;
+    // Get Focus window
+    XGetInputFocus(display, &focusWindow, &revert);
+
+    ecore_x_window_prop_property_set(focusWindow,
+                                      ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+                                      ECORE_X_ATOM_CARDINAL, 32, &angle, 1);
+    XCloseDisplay(display);
+  }
+}
+
+void SetReturnKeyType( const InputMethod::ActionButton type )
+{
+  Dali::ImfManager imfManager = ImfManager::Get(); // Create ImfManager instance (if required) when setting values
+  Ecore_IMF_Context* imfContext = reinterpret_cast<Ecore_IMF_Context*>( imfManager.GetContext() );
+
+  if( imfContext )
+  {
+    gActionButtonFunction = type;
+    ecore_imf_context_input_panel_return_key_type_set( imfContext, actionButtonMapping( type ) );
+  }
+}
+
+Dali::InputMethod::ActionButton GetReturnKeyType()
+{
+  return gActionButtonFunction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/window-extensions.cpp b/adaptors/x11/window-extensions.cpp
new file mode 100644 (file)
index 0000000..81566b1
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <window-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <string>
+#include <sstream>
+#include <Ecore.h>
+#include <Ecore_X.h>
+
+// INTERNAL INCLUDES
+#include <window.h>
+
+namespace
+{
+typedef std::vector< std::string > HintContainer;
+
+const char* HINT_EFFECT_NAME = "wm.comp.win.effect.enable";
+const char* HINT_ENABLE_POSTFIX = ":1";
+const char* HINT_DISABLE_POSTFIX = ":0";
+
+void Tokenize(const std::string& str, HintContainer& hints, const std::string& delimiters = ",")
+{
+  std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+  std::string::size_type pos = str.find_first_of(delimiters, lastPos);
+
+  while (std::string::npos != pos || std::string::npos != lastPos)
+  {
+    hints.push_back(str.substr(lastPos, pos - lastPos));
+    lastPos = str.find_first_not_of(delimiters, pos);
+    pos = str.find_first_of(delimiters, lastPos);
+  }
+}
+
+void GetAppliedHints( Dali::Window window, HintContainer& hints )
+{
+  Dali::Any nativeWindow = window.GetNativeHandle();
+  if ( !nativeWindow.Empty() )
+  {
+    Ecore_X_Window ecoreWindow;
+    nativeWindow.Get( ecoreWindow );
+
+    unsigned char* data = NULL;
+    int n = 0;
+    int res = ecore_x_window_prop_property_get( ecoreWindow, ECORE_X_ATOM_E_WINDOW_AUX_HINT_SUPPORTED_LIST,
+                                                ECORE_X_ATOM_STRING, 0, &data, &n );
+
+    if ((res == 8) && (n > 0))
+    {
+      std::stringstream ss;
+      ss << data;
+      Tokenize(ss.str(), hints);
+    }
+
+    free(data);
+  }
+}
+
+}
+
+namespace Dali
+{
+
+namespace WindowExtensions
+{
+
+void EnableEffect( Window window, bool enable )
+{
+  Any nativeWindow = window.GetNativeHandle();
+
+  DALI_ASSERT_ALWAYS( !nativeWindow.Empty() && "Empty window!!!" );
+
+  HintContainer hints;
+  GetAppliedHints( window, hints );
+
+  std::stringstream ss;
+  ss << hints.size() << ":" << HINT_EFFECT_NAME << (enable ? HINT_ENABLE_POSTFIX : HINT_DISABLE_POSTFIX);
+
+  // Applied the window effect to the current window.
+  Ecore_X_Window ecoreWindow;
+  nativeWindow.Get(ecoreWindow);
+  ecore_x_window_prop_property_set( ecoreWindow, ECORE_X_ATOM_E_WINDOW_AUX_HINT,
+                                    ECORE_X_ATOM_STRING, 8,
+                                    (void*)ss.str().c_str(), ss.str().size() + 1 );
+}
+
+bool IsEffectEnabled( Window window )
+{
+  Any nativeWindow = window.GetNativeHandle();
+
+  DALI_ASSERT_ALWAYS( !nativeWindow.Empty() && "Empty window!!!" );
+
+  HintContainer hints;
+  GetAppliedHints( window, hints );
+
+  HintContainer::iterator iter = std::find( hints.begin(), hints.end(), HINT_EFFECT_NAME );
+
+  return iter != hints.end();
+}
+
+} // namespace WindowExtensions
+
+} // namespace Dali
+
+
diff --git a/adaptors/x11/window-extensions.h b/adaptors/x11/window-extensions.h
new file mode 100644 (file)
index 0000000..243d006
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __DALI_WINDOW_EXTENSIONS_H__
+#define __DALI_WINDOW_EXTENSIONS_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+class Window;
+
+namespace WindowExtensions
+{
+
+/**
+ * @brief Set whether the effect will enable or not.
+ *
+ * The effect will be shown when the application is launched, quit, shown and hiden.
+ *
+ * @note This function is only specified by tizen.
+ *
+ * @param[in] window The window to set.
+ * @param[in] enable True if the effect is enabled.
+ */
+DALI_IMPORT_API void EnableEffect( Window window, bool enable );
+
+/**
+ * @brief Retrieve whether the effect is enabled or not.
+ *
+ * @note This function is only specified by tizen.
+ *
+ * @param[in] window The window to set.
+ * @return True if the effect is enabled.
+ */
+DALI_IMPORT_API bool IsEffectEnabled( Window window );
+
+} // namespace WindowExtensions
+
+} // namespace Dali
+
+#endif // __DALI_WINDOW_EXTENSIONS_H__
diff --git a/adaptors/x11/window-impl-x.cpp b/adaptors/x11/window-impl-x.cpp
new file mode 100644 (file)
index 0000000..23fae2d
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "window-impl.h"
+
+// EXTERNAL HEADERS
+#include <Ecore.h>
+#include <Ecore_X.h>
+
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/system-overlay.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+
+// INTERNAL HEADERS
+#include <window-render-surface.h>
+#include <drag-and-drop-detector-impl.h>
+#include <indicator-impl.h>
+#include <window-visibility-observer.h>
+#include <orientation.h>
+#include <orientation-impl.h>
+
+namespace
+{
+const float INDICATOR_ANIMATION_DURATION( 0.18f ); // 180 milli seconds
+const float INDICATOR_SHOW_Y_POSITION( 0.0f );
+const float INDICATOR_HIDE_Y_POSITION( -52.0f );
+}
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_WINDOW");
+#endif
+
+/**
+ * TODO: Abstract Window class out and move this into a window implementation for Ecore
+ */
+struct Window::EventHandler
+{
+  /**
+   * Constructor
+   * @param[in]  window  A pointer to the window class.
+   */
+  EventHandler( Window* window )
+  : mWindow( window ),
+    mWindowPropertyHandler( NULL ),
+    mClientMessagehandler( NULL ),
+    mWindowDeleteRequestHandler( NULL ),
+    mEcoreWindow( 0 )
+  {
+    // store ecore window handle
+    ECore::WindowRenderSurface* x11Window( dynamic_cast< ECore::WindowRenderSurface * >( mWindow->mSurface ) );
+    if( x11Window )
+    {
+      mEcoreWindow = x11Window->GetXWindow();
+    }
+    DALI_ASSERT_ALWAYS( mEcoreWindow != 0 && "There is no ecore x window");
+
+#ifndef DALI_PROFILE_UBUNTU
+    // set property on window to get deiconify approve client message
+    unsigned int tmp = 1;
+    ecore_x_window_prop_card32_set(mEcoreWindow,
+                             ECORE_X_ATOM_E_DEICONIFY_APPROVE,
+                             &tmp, 1);
+#endif // DALI_PROFILE_UBUNTU
+
+    if( mWindow->mEcoreEventHander )
+    {
+      ecore_x_input_multi_select( mEcoreWindow );
+
+      // This ensures that we catch the window close (or delete) request
+      ecore_x_icccm_protocol_set( mEcoreWindow, ECORE_X_WM_PROTOCOL_DELETE_REQUEST, EINA_TRUE );
+
+      mWindowPropertyHandler=  ecore_event_handler_add( ECORE_X_EVENT_WINDOW_PROPERTY,  EcoreEventWindowPropertyChanged, this );
+      mClientMessagehandler =  ecore_event_handler_add( ECORE_X_EVENT_CLIENT_MESSAGE,  EcoreEventClientMessage, this );
+      mWindowDeleteRequestHandler = ecore_event_handler_add( ECORE_X_EVENT_WINDOW_DELETE_REQUEST, EcoreEventWindowDeleteRequest, this );
+    }
+  }
+
+  /**
+   * Destructor
+   */
+  ~EventHandler()
+  {
+    if ( mWindowPropertyHandler )
+    {
+      ecore_event_handler_del( mWindowPropertyHandler );
+    }
+    if ( mClientMessagehandler )
+    {
+      ecore_event_handler_del( mClientMessagehandler );
+    }
+    if ( mWindowDeleteRequestHandler )
+    {
+      ecore_event_handler_del( mWindowDeleteRequestHandler );
+    }
+  }
+
+  // Static methods
+
+  /// Called when the window properties are changed.
+  static Eina_Bool EcoreEventWindowPropertyChanged( void* data, int type, void* event )
+  {
+    Ecore_X_Event_Window_Property* propertyChangedEvent( (Ecore_X_Event_Window_Property*)event );
+    EventHandler* handler( (EventHandler*)data );
+    Eina_Bool handled( ECORE_CALLBACK_PASS_ON );
+
+    if ( handler && handler->mWindow )
+    {
+      WindowVisibilityObserver* observer( handler->mWindow->mAdaptor );
+      if ( observer && ( propertyChangedEvent->win == handler->mEcoreWindow ) )
+      {
+        Ecore_X_Window_State_Hint state( ecore_x_icccm_state_get( propertyChangedEvent->win ) );
+
+        switch ( state )
+        {
+          case ECORE_X_WINDOW_STATE_HINT_WITHDRAWN:
+          {
+            // Window was hidden.
+            observer->OnWindowHidden();
+            DALI_LOG_INFO( gWindowLogFilter, Debug::General, "Window (%d) Withdrawn\n", handler->mEcoreWindow );
+            handled = ECORE_CALLBACK_DONE;
+          }
+          break;
+
+          case ECORE_X_WINDOW_STATE_HINT_ICONIC:
+          {
+            // Window was iconified (minimised).
+            observer->OnWindowHidden();
+            DALI_LOG_INFO( gWindowLogFilter, Debug::General, "Window (%d) Iconfied\n", handler->mEcoreWindow );
+            handled = ECORE_CALLBACK_DONE;
+          }
+          break;
+
+          case ECORE_X_WINDOW_STATE_HINT_NORMAL:
+          {
+            // Window was shown.
+            observer->OnWindowShown();
+            DALI_LOG_INFO( gWindowLogFilter, Debug::General, "Window (%d) Shown\n", handler->mEcoreWindow );
+            handled = ECORE_CALLBACK_DONE;
+          }
+          break;
+
+          default:
+            // Ignore
+            break;
+        }
+      }
+    }
+
+    return handled;
+  }
+
+  /// Called when the window properties are changed.
+  static Eina_Bool EcoreEventClientMessage( void* data, int type, void* event )
+  {
+    Eina_Bool handled( ECORE_CALLBACK_PASS_ON );
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Event_Client_Message* clientMessageEvent( (Ecore_X_Event_Client_Message*)event );
+    EventHandler* handler( (EventHandler*)data );
+
+    if (clientMessageEvent->message_type == ECORE_X_ATOM_E_DEICONIFY_APPROVE)
+    {
+      ECore::WindowRenderSurface* x11Window( dynamic_cast< ECore::WindowRenderSurface * >( handler->mWindow->mSurface ) );
+      WindowVisibilityObserver* observer( handler->mWindow->mAdaptor );
+
+      if ( observer && ( (unsigned int)clientMessageEvent->data.l[0] == handler->mEcoreWindow ) )
+      {
+        if (clientMessageEvent->data.l[1] == 0) //wm sends request message using value 0
+        {
+          observer->OnWindowShown();
+
+          // request to approve the deiconify. render-surface should send proper event after real rendering
+          if(x11Window)
+          {
+            x11Window->RequestToApproveDeiconify();
+          }
+
+          handled = ECORE_CALLBACK_DONE;
+        }
+      }
+    }
+#endif // DALI_PROFILE_UBUNTU
+
+    return handled;
+  }
+
+  /// Called when the window receives a delete request
+  static Eina_Bool EcoreEventWindowDeleteRequest( void* data, int type, void* event )
+  {
+    EventHandler* handler( (EventHandler*)data );
+    handler->mWindow->mDeleteRequestSignal.Emit();
+    return ECORE_CALLBACK_DONE;
+  }
+
+  // Data
+  Window* mWindow;
+  Ecore_Event_Handler* mWindowPropertyHandler;
+  Ecore_Event_Handler* mClientMessagehandler;
+  Ecore_Event_Handler* mWindowDeleteRequestHandler;
+  Ecore_X_Window mEcoreWindow;
+};
+
+
+Window* Window::New(const PositionSize& posSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Window* window = new Window();
+  window->mIsTransparent = isTransparent;
+  window->Initialize(posSize, name, className);
+  return window;
+}
+
+void Window::SetAdaptor(Dali::Adaptor& adaptor)
+{
+  DALI_ASSERT_ALWAYS( !mStarted && "Adaptor already started" );
+  mStarted = true;
+
+  // Only create one overlay per window
+  Internal::Adaptor::Adaptor& adaptorImpl = Internal::Adaptor::Adaptor::GetImplementation(adaptor);
+  Integration::Core& core = adaptorImpl.GetCore();
+  mOverlay = &core.GetSystemOverlay();
+
+  Dali::RenderTaskList taskList = mOverlay->GetOverlayRenderTasks();
+  taskList.CreateTask();
+
+  mAdaptor = &adaptorImpl;
+  mAdaptor->AddObserver( *this );
+
+  // Can only create the detector when we know the Core has been instantiated.
+  mDragAndDropDetector = DragAndDropDetector::New();
+  mAdaptor->SetDragAndDropDetector( &GetImplementation( mDragAndDropDetector ) );
+
+  if( mOrientation )
+  {
+    mOrientation->SetAdaptor(adaptor);
+  }
+
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetAdaptor(mAdaptor);
+  }
+}
+
+RenderSurface* Window::GetSurface()
+{
+  return mSurface;
+}
+
+void Window::ShowIndicator( Dali::Window::IndicatorVisibleMode visibleMode )
+{
+  DALI_LOG_TRACE_METHOD_FMT( gWindowLogFilter, "visible : %d\n", visibleMode );
+  DALI_ASSERT_DEBUG(mOverlay);
+
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  DALI_ASSERT_DEBUG(x11Window);
+  Ecore_X_Window xWinId = x11Window->GetXWindow();
+
+  mIndicatorVisible = visibleMode;
+
+  if ( mIndicatorVisible == Dali::Window::VISIBLE )
+  {
+    // when the indicator is visible, set proper mode for indicator server according to bg mode
+    if ( mIndicatorOpacityMode == Dali::Window::OPAQUE )
+    {
+      ecore_x_e_illume_indicator_opacity_set(xWinId, ECORE_X_ILLUME_INDICATOR_OPAQUE);
+    }
+    else if ( mIndicatorOpacityMode == Dali::Window::TRANSLUCENT )
+    {
+      ecore_x_e_illume_indicator_opacity_set(xWinId, ECORE_X_ILLUME_INDICATOR_TRANSLUCENT);
+    }
+#if defined(DALI_PROFILE_MOBILE)
+    else if ( mIndicatorOpacityMode == Dali::Window::TRANSPARENT )
+    {
+      ecore_x_e_illume_indicator_opacity_set(xWinId, ECORE_X_ILLUME_INDICATOR_OPAQUE);
+    }
+#endif
+  }
+  else
+  {
+    // when the indicator is not visible, set TRANSPARENT mode for indicator server
+    ecore_x_e_illume_indicator_opacity_set(xWinId, ECORE_X_ILLUME_INDICATOR_TRANSPARENT); // it means hidden indicator
+  }
+
+  DoShowIndicator( mIndicatorOrientation );
+}
+
+void Window::RotateIndicator(Dali::Window::WindowOrientation orientation)
+{
+  DALI_LOG_TRACE_METHOD_FMT( gWindowLogFilter, "Orientation: %d\n", orientation );
+
+  DoRotateIndicator( orientation );
+}
+
+void Window::SetIndicatorBgOpacity( Dali::Window::IndicatorBgOpacity opacityMode )
+{
+  mIndicatorOpacityMode = opacityMode;
+
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetOpacityMode( opacityMode );
+  }
+}
+
+void Window::SetClass(std::string name, std::string klass)
+{
+  // Get render surface's x11 window
+  if( mSurface )
+  {
+    ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+    if( x11Window )
+    {
+      ecore_x_icccm_name_class_set( x11Window->GetXWindow(), name.c_str(), klass.c_str() );
+    }
+  }
+}
+
+Window::Window()
+: mSurface(NULL),
+  mIndicatorVisible(Dali::Window::INVISIBLE),
+  mIndicatorIsShown(false),
+  mShowRotatedIndicatorOnClose(false),
+  mStarted(false),
+  mIsTransparent(false),
+  mWMRotationAppSet(false),
+  mEcoreEventHander(true),
+  mIndicator(NULL),
+  mIndicatorOrientation(Dali::Window::PORTRAIT),
+  mNextIndicatorOrientation(Dali::Window::PORTRAIT),
+  mIndicatorOpacityMode(Dali::Window::OPAQUE),
+  mOverlay(NULL),
+  mAdaptor(NULL),
+  mEventHandler(NULL),
+  mPreferredOrientation(Dali::Window::PORTRAIT)
+{
+
+  // Detect if we're not running in a ecore main loop (e.g. libuv).
+  // Typically ecore_x_init is called by app_efl_main->elm_init
+  // but if we're not using app_efl_main then we have to call it ourselves
+  // This is a hack until we create a pure X Window class
+  if( ecore_x_display_get() == NULL )
+  {
+    mEcoreEventHander = false;
+    ecore_x_init (NULL); //  internally calls _ecore_x_input_init
+  }
+
+}
+
+Window::~Window()
+{
+  delete mEventHandler;
+
+  if( mIndicator )
+  {
+    mOverlay->Remove( mIndicator->GetActor() );
+    Dali::RenderTaskList taskList = mOverlay->GetOverlayRenderTasks();
+    Dali::RenderTask indicatorTask = taskList.GetTask(0);
+    mOverlay->GetOverlayRenderTasks().RemoveTask(indicatorTask);
+    mIndicator->Close();
+    delete mIndicator;
+  }
+
+  if( mAdaptor )
+  {
+    mAdaptor->RemoveObserver( *this );
+    mAdaptor->SetDragAndDropDetector( NULL );
+    mAdaptor = NULL;
+  }
+
+  delete mSurface;
+}
+
+void Window::Initialize(const PositionSize& windowPosition, const std::string& name, const std::string& className)
+{
+  // create an X11 window by default
+  Any surface;
+  ECore::WindowRenderSurface* windowSurface = new ECore::WindowRenderSurface( windowPosition, surface, name, className, mIsTransparent );
+  windowSurface->Map();
+
+  mSurface = windowSurface;
+
+  mOrientation = Orientation::New(this);
+
+  // create event handler for X11 window
+  mEventHandler = new EventHandler( this );
+}
+
+void Window::DoShowIndicator( Dali::Window::WindowOrientation lastOrientation )
+{
+  if( mIndicator == NULL )
+  {
+    if( mIndicatorVisible != Dali::Window::INVISIBLE )
+    {
+      mIndicator = new Indicator( mAdaptor, mIndicatorOrientation, this );
+      mIndicator->SetOpacityMode( mIndicatorOpacityMode );
+      Dali::Actor actor = mIndicator->GetActor();
+      SetIndicatorActorRotation();
+      mOverlay->Add(actor);
+    }
+    // else don't create a hidden indicator
+  }
+  else // Already have indicator
+  {
+    if( mIndicatorVisible == Dali::Window::VISIBLE )
+    {
+      // If we are resuming, and rotation has changed,
+      if( mIndicatorIsShown == false && mIndicatorOrientation != mNextIndicatorOrientation )
+      {
+        // then close current indicator and open new one
+        mShowRotatedIndicatorOnClose = true;
+        mIndicator->Close(); // May synchronously call IndicatorClosed() callback & 1 level of recursion
+        // Don't show actor - will contain indicator for old orientation.
+      }
+    }
+  }
+
+  // set indicator visible mode
+  if( mIndicator != NULL )
+  {
+    mIndicator->SetVisible( mIndicatorVisible );
+  }
+
+  bool show = (mIndicatorVisible != Dali::Window::INVISIBLE );
+  SetIndicatorProperties( show, lastOrientation );
+  mIndicatorIsShown = show;
+}
+
+void Window::DoRotateIndicator( Dali::Window::WindowOrientation orientation )
+{
+  if( mIndicatorIsShown )
+  {
+    mShowRotatedIndicatorOnClose = true;
+    mNextIndicatorOrientation = orientation;
+    mIndicator->Close(); // May synchronously call IndicatorClosed() callback
+  }
+  else
+  {
+    // Save orientation for when the indicator is next shown
+    mShowRotatedIndicatorOnClose = false;
+    mNextIndicatorOrientation = orientation;
+  }
+}
+
+void Window::SetIndicatorProperties( bool isShow, Dali::Window::WindowOrientation lastOrientation )
+{
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+    Ecore_X_Window win = x11Window->GetXWindow();
+
+    int show_state = static_cast<int>( isShow );
+    ecore_x_window_prop_property_set( win,
+                                      ECORE_X_ATOM_E_ILLUME_INDICATOR_STATE,
+                                      ECORE_X_ATOM_CARDINAL, 32, &show_state, 1);
+
+    if ( isShow )
+    {
+      ecore_x_e_illume_indicator_state_set(win, ECORE_X_ILLUME_INDICATOR_STATE_ON);
+    }
+    else
+    {
+      ecore_x_e_illume_indicator_state_set(win, ECORE_X_ILLUME_INDICATOR_STATE_OFF);
+    }
+  }
+}
+
+void Window::IndicatorTypeChanged(Indicator::Type type)
+{
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Window win = x11Window->GetXWindow();
+    switch(type)
+    {
+      case Indicator::INDICATOR_TYPE_1:
+        ecore_x_e_illume_indicator_type_set( win, ECORE_X_ILLUME_INDICATOR_TYPE_1 );
+        break;
+
+      case Indicator::INDICATOR_TYPE_2:
+        ecore_x_e_illume_indicator_type_set( win, ECORE_X_ILLUME_INDICATOR_TYPE_2 );
+        break;
+
+      case Indicator::INDICATOR_TYPE_UNKNOWN:
+      default:
+        break;
+    }
+#endif // DALI_PROFILE_UBUNTU
+  }
+}
+
+void Window::IndicatorClosed( Indicator* indicator )
+{
+  DALI_LOG_TRACE_METHOD( gWindowLogFilter );
+
+  if( mShowRotatedIndicatorOnClose )
+  {
+    Dali::Window::WindowOrientation currentOrientation = mIndicatorOrientation;
+    mIndicator->Open(mNextIndicatorOrientation);
+    mIndicatorOrientation = mNextIndicatorOrientation;
+    SetIndicatorActorRotation();
+    DoShowIndicator(currentOrientation);
+  }
+}
+
+void Window::IndicatorVisibilityChanged(bool isVisible)
+{
+  mIndicatorVisibilityChangedSignal.Emit(isVisible);
+}
+
+void Window::SetIndicatorActorRotation()
+{
+  DALI_LOG_TRACE_METHOD( gWindowLogFilter );
+  DALI_ASSERT_DEBUG( mIndicator != NULL );
+
+  Dali::Actor actor = mIndicator->GetActor();
+  switch( mIndicatorOrientation )
+  {
+    case Dali::Window::PORTRAIT:
+      actor.SetParentOrigin( ParentOrigin::TOP_CENTER );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(0), Vector3::ZAXIS );
+      break;
+    case Dali::Window::PORTRAIT_INVERSE:
+      actor.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(180), Vector3::ZAXIS );
+      break;
+    case Dali::Window::LANDSCAPE:
+      actor.SetParentOrigin( ParentOrigin::CENTER_LEFT );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(270), Vector3::ZAXIS );
+      break;
+    case Dali::Window::LANDSCAPE_INVERSE:
+      actor.SetParentOrigin( ParentOrigin::CENTER_RIGHT );
+      actor.SetAnchorPoint(  AnchorPoint::TOP_CENTER );
+      actor.SetOrientation( Degree(90), Vector3::ZAXIS );
+      break;
+  }
+}
+
+void Window::Raise()
+{
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+    Ecore_X_Window win = x11Window->GetXWindow();
+    ecore_x_window_raise(win);
+  }
+}
+
+void Window::Lower()
+{
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+    Ecore_X_Window win = x11Window->GetXWindow();
+    ecore_x_window_lower(win);
+  }
+}
+
+void Window::Activate()
+{
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+    Ecore_X_Window win = x11Window->GetXWindow();
+    ecore_x_netwm_client_active_request(ecore_x_window_root_get(win), win, 1 /* request type, 1:application, 2:pager */, 0);
+  }
+}
+
+Dali::DragAndDropDetector Window::GetDragAndDropDetector() const
+{
+  return mDragAndDropDetector;
+}
+
+Dali::Any Window::GetNativeHandle() const
+{
+  if(mEventHandler)
+  {
+    return mEventHandler->mEcoreWindow;
+  }
+  else
+  {
+    return Dali::Any();
+  }
+}
+
+void Window::OnStart()
+{
+  ShowIndicator( mIndicatorVisible );
+}
+
+void Window::OnPause()
+{
+}
+
+void Window::OnResume()
+{
+  // resume indicator status
+  if( mIndicator != NULL )
+  {
+    // Restore own indicator opacity
+    // Send opacity mode to indicator service when app resumed
+    mIndicator->SetOpacityMode( mIndicatorOpacityMode );
+  }
+}
+
+void Window::OnStop()
+{
+  if( mIndicator )
+  {
+    mIndicator->Close();
+  }
+
+  delete mIndicator;
+  mIndicator = NULL;
+}
+
+void Window::OnDestroy()
+{
+  mAdaptor = NULL;
+}
+
+void Window::AddAvailableOrientation(Dali::Window::WindowOrientation orientation)
+{
+  bool found = false;
+
+  for( std::size_t i=0; i<mAvailableOrientations.size(); i++ )
+  {
+    if(mAvailableOrientations[i] == orientation)
+    {
+      found = true;
+      break;
+    }
+  }
+
+  if( ! found )
+  {
+    mAvailableOrientations.push_back(orientation);
+    SetAvailableOrientations( mAvailableOrientations );
+  }
+}
+
+void Window::RemoveAvailableOrientation(Dali::Window::WindowOrientation orientation)
+{
+  for( std::vector<Dali::Window::WindowOrientation>::iterator iter = mAvailableOrientations.begin();
+       iter != mAvailableOrientations.end(); ++iter )
+  {
+    if( *iter == orientation )
+    {
+      mAvailableOrientations.erase( iter );
+      break;
+    }
+  }
+  SetAvailableOrientations( mAvailableOrientations );
+}
+
+void Window::SetAvailableOrientations(const std::vector<Dali::Window::WindowOrientation>& orientations)
+{
+  DALI_ASSERT_ALWAYS( mAvailableOrientations.size() <= 4 && "Incorrect number of available orientations" );
+
+  mAvailableOrientations = orientations;
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Window ecoreWindow = x11Window->GetXWindow();
+    if( ! mWMRotationAppSet )
+    {
+      mWMRotationAppSet = true;
+      ecore_x_e_window_rotation_app_set(ecoreWindow, EINA_TRUE);
+    }
+
+    int rotations[4];
+    for( std::size_t i=0; i<mAvailableOrientations.size(); i++ )
+    {
+      rotations[i] = static_cast<int>(mAvailableOrientations[i]);
+    }
+    ecore_x_e_window_rotation_available_rotations_set(ecoreWindow, rotations, mAvailableOrientations.size() );
+#endif // DALI_PROFILE_UBUNTU
+  }
+}
+
+const std::vector<Dali::Window::WindowOrientation>& Window::GetAvailableOrientations()
+{
+  return mAvailableOrientations;
+}
+
+void Window::SetPreferredOrientation(Dali::Window::WindowOrientation orientation)
+{
+  mPreferredOrientation = orientation;
+
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Window ecoreWindow = x11Window->GetXWindow();
+
+    if( ! mWMRotationAppSet )
+    {
+      mWMRotationAppSet = true;
+      ecore_x_e_window_rotation_app_set(ecoreWindow, EINA_TRUE);
+    }
+
+    ecore_x_e_window_rotation_preferred_rotation_set(ecoreWindow, orientation);
+#endif // DALI_PROFILE_UBUNTU
+  }
+}
+
+Dali::Window::WindowOrientation Window::GetPreferredOrientation()
+{
+  return mPreferredOrientation;
+}
+
+void Window::RotationDone( int orientation, int width, int height )
+{
+  // Tell window manager we're done
+  ECore::WindowRenderSurface* x11Window = dynamic_cast< ECore::WindowRenderSurface * >( mSurface );
+  if( x11Window )
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    Ecore_X_Window ecoreWindow = x11Window->GetXWindow();
+    Ecore_X_Window root = ecore_x_window_root_get(ecoreWindow);
+
+    /**
+     * send rotation done message to wm, even if window is already rotated.
+     * that's why wm must be wait for comming rotation done message
+     * after sending rotation request.
+     */
+    ecore_x_e_window_rotation_change_done_send(root, ecoreWindow, orientation, width, height);
+
+    /**
+     * set rotate window property
+     */
+    int angles[2] = { orientation, orientation };
+    ecore_x_window_prop_property_set( ecoreWindow,
+                                     ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+                                     ECORE_X_ATOM_CARDINAL, 32, &angles, 2 );
+#endif // DALI_PROFILE_UBUNTU
+  }
+}
+
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/adaptors/x11/window-render-surface-x.cpp b/adaptors/x11/window-render-surface-x.cpp
new file mode 100644 (file)
index 0000000..0580f54
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "window-render-surface.h"
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <X11/extensions/Xfixes.h> // for damage notify
+#include <X11/extensions/Xdamage.h> // for damage notify
+
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+#include <ecore-x-types.h>
+#include <trigger-event.h>
+#include <gl/egl-implementation.h>
+#include <base/display-connection.h>
+
+namespace Dali
+{
+
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gRenderSurfaceLogFilter;
+#endif
+
+namespace ECore
+{
+
+namespace
+{
+
+const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
+
+} // unnamed namespace
+
+WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize,
+                                          Any surface,
+                                          const std::string& name,
+                                          const std::string& className,
+                                          bool isTransparent)
+: EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
+  mNeedToApproveDeiconify(false),
+  mClassName(className)
+{
+  DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
+  Init( surface );
+}
+
+WindowRenderSurface::~WindowRenderSurface()
+{
+  if( mOwnSurface )
+  {
+    ecore_x_window_free( mX11Window );
+  }
+}
+
+Ecore_X_Drawable WindowRenderSurface::GetDrawable()
+{
+  // already an e-core type
+  return (Ecore_X_Drawable)mX11Window;
+}
+
+Any WindowRenderSurface::GetSurface()
+{
+  // already an e-core type
+  return Any( mX11Window );
+}
+
+Ecore_X_Window WindowRenderSurface::GetXWindow()
+{
+  return mX11Window;
+}
+
+void WindowRenderSurface::RequestToApproveDeiconify()
+{
+  mNeedToApproveDeiconify = true;
+}
+
+void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+
+  eglImpl.ChooseConfig(true, mColorDepth);
+}
+
+void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+
+  // create the EGL surface
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XWindow window = static_cast< XWindow>( mX11Window );
+  eglImpl.CreateSurfaceWindow( (EGLNativeWindowType)window, mColorDepth ); // reinterpret_cast does not compile
+}
+
+void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
+  eglImpl.DestroySurface();
+}
+
+bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
+{
+  DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
+
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XWindow window = static_cast< XWindow >( mX11Window );
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+
+  return eglImpl.ReplaceSurfaceWindow( (EGLNativeWindowType)window ); // reinterpret_cast does not compile
+}
+
+void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
+{
+  bool needToMove = false;
+  bool needToResize = false;
+
+  // check moving
+  if( (fabs(positionSize.x - mPosition.x) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.y - mPosition.y) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToMove = true;
+  }
+
+  // check resizing
+  if( (fabs(positionSize.width - mPosition.width) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.height - mPosition.height) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToResize = true;
+  }
+
+  if( needToMove &&  needToResize)
+  {
+    ecore_x_window_move_resize(mX11Window, positionSize.x, positionSize.y, positionSize.width, positionSize.height);
+    mPosition = positionSize;
+  }
+  else if(needToMove)
+  {
+    ecore_x_window_move(mX11Window, positionSize.x, positionSize.y);
+    mPosition = positionSize;
+  }
+  else if (needToResize)
+  {
+    ecore_x_window_resize(mX11Window, positionSize.width, positionSize.height);
+    mPosition = positionSize;
+  }
+
+}
+
+void WindowRenderSurface::Map()
+{
+  ecore_x_window_show(mX11Window);
+}
+
+void WindowRenderSurface::StartRender()
+{
+}
+
+bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
+{
+  // nothing to do for windows
+  return true;
+}
+
+void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
+{
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
+  eglImpl.SwapBuffers();
+
+  // When the window is deiconified, it approves the deiconify operation to window manager after rendering
+  if(mNeedToApproveDeiconify)
+  {
+    // SwapBuffer is desychronized. So make sure to sychronize when window is deiconified.
+    glAbstraction.Finish();
+
+    XDisplay* display = AnyCast<XDisplay *>(displayConnection->GetDisplay());
+
+#ifndef DALI_PROFILE_UBUNTU
+    /* client sends immediately reply message using value 1 */
+    XEvent xev;
+
+    xev.xclient.window = mX11Window;
+    xev.xclient.type = ClientMessage;
+    xev.xclient.message_type = ECORE_X_ATOM_E_DEICONIFY_APPROVE;
+    xev.xclient.format = 32;
+    xev.xclient.data.l[0] = mX11Window;
+    xev.xclient.data.l[1] = 1;
+    xev.xclient.data.l[2] = 0;
+    xev.xclient.data.l[3] = 0;
+    xev.xclient.data.l[4] = 0;
+
+    XSendEvent(display, mX11Window, false, ECORE_X_EVENT_MASK_WINDOW_CONFIGURE, &xev);
+#endif // DALI_PROFILE_UBUNTU
+
+    XSync(display, false);
+
+    mNeedToApproveDeiconify = false;
+  }
+}
+
+void WindowRenderSurface::StopRender()
+{
+}
+
+void WindowRenderSurface::SetViewMode( ViewMode viewMode )
+{
+  Ecore_X_Atom viewModeAtom( ecore_x_atom_get( "_E_COMP_3D_APP_WIN" ) );
+
+  if( viewModeAtom != None )
+  {
+    unsigned int value( static_cast<unsigned int>( viewMode ) );
+    ecore_x_window_prop_card32_set( mX11Window, viewModeAtom, &value, 1 );
+  }
+}
+
+void WindowRenderSurface::CreateXRenderable()
+{
+   // if width or height are zero, go full screen.
+  if ( (mPosition.width == 0) || (mPosition.height == 0) )
+  {
+    // Default window size == screen size
+    mPosition.x = 0;
+    mPosition.y = 0;
+
+    ecore_x_screen_size_get( ecore_x_default_screen_get(), &mPosition.width, &mPosition.height );
+  }
+
+  if(mColorDepth == COLOR_DEPTH_32)
+  {
+    // create 32 bit window
+    mX11Window = ecore_x_window_argb_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height );
+  }
+  else
+  {
+    // create 24 bit window
+    mX11Window = ecore_x_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height );
+  }
+
+  if ( mX11Window == 0 )
+  {
+      DALI_ASSERT_ALWAYS(0 && "Failed to create X window");
+  }
+
+  // set up window title which will be helpful for debug utitilty
+  ecore_x_icccm_title_set( mX11Window, mTitle.c_str() );
+  ecore_x_netwm_name_set( mX11Window, mTitle.c_str() );
+  ecore_x_icccm_name_class_set( mX11Window, mTitle.c_str(), mClassName.c_str() );
+
+  // set up etc properties to match with ecore-evas
+  char *id = NULL;
+  if( ( id = getenv("DESKTOP_STARTUP_ID") ) )
+  {
+    ecore_x_netwm_startup_id_set( mX11Window, id );
+  }
+
+  ecore_x_icccm_hints_set( mX11Window,
+                           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
+
+  // we SHOULD guarantee the x11 window was created in x server.
+  ecore_x_sync();
+}
+
+void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
+{
+  mX11Window = static_cast< Ecore_X_Window >( surfaceId );
+}
+
+void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& /* threadSynchronization */ )
+{
+  // Nothing to do.
+}
+
+void WindowRenderSurface::ReleaseLock()
+{
+  // Nothing to do.
+}
+
+} // namespace ECore
+
+} // namespace Dali
diff --git a/adaptors/x11/window-render-surface.h b/adaptors/x11/window-render-surface.h
new file mode 100644 (file)
index 0000000..f9b5b41
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef __DALI_INTERNAL_ECORE_X_WINDOW_RENDER_SURFACE_H__
+#define __DALI_INTERNAL_ECORE_X_WINDOW_RENDER_SURFACE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <ecore-x-render-surface.h>
+
+namespace Dali
+{
+
+namespace ECore
+{
+
+/**
+ * @copydoc Dali::ECore::EcoreXRenderSurface.
+ * Window specialization.
+ */
+class WindowRenderSurface : public EcoreXRenderSurface
+{
+public:
+
+  /**
+    * Uses an X11 surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a X-window or X-pixmap (type must be unsigned int).
+    * @param [in] name optional name of surface passed in
+    * @param [in] className optional class name of the surface passed in
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  WindowRenderSurface( Dali::PositionSize positionSize,
+                       Any surface,
+                       const std::string& name,
+                       const std::string& className,
+                       bool isTransparent = false );
+
+  /**
+   * @copydoc Dali::ECore::EcoreXRenderSurface::~EcoreXRenderSurface
+   */
+  virtual ~WindowRenderSurface();
+
+public: // API
+
+  /**
+   * @copydoc Dali::RenderSurface::GetDrawable()
+   */
+  virtual Ecore_X_Drawable GetDrawable();
+
+  /**
+   * Request to approve deiconify operation
+   * If it is requested, it will send ECORE_X_ATOM_E_DEICONIFY_APPROVE event to window manager after rendering
+   */
+  void RequestToApproveDeiconify();
+
+  /**
+   * Map window
+   */
+  virtual void Map();
+
+  /**
+   * @copydoc Dali::ECore::EcoreXRenderSurface::GetSurface()
+   */
+  virtual Any GetSurface();
+
+  /**
+   * @copydoc Dali::ECore::EcoreXRenderSurface::GetXWindow()
+   */
+  virtual Ecore_X_Window GetXWindow();
+
+public: // from Dali::RenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurface::InitializeEgl()
+   */
+  virtual void InitializeEgl( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::CreateEglSurface()
+   */
+  virtual void CreateEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::DestroyEglSurface()
+   */
+  virtual void DestroyEglSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReplaceEGLSurface()
+   */
+  virtual bool ReplaceEGLSurface( EglInterface& egl );
+
+  /**
+   * @copydoc Dali::RenderSurface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize);
+
+  /**
+   * @copydoc Dali::RenderSurface::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::RenderSurface::StartRender()
+   */
+  virtual void StartRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::PreRender()
+   */
+  virtual bool PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction );
+
+  /**
+   * @copydoc Dali::RenderSurface::PostRender()
+   */
+  virtual void PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurface::StopRender()
+   */
+  virtual void StopRender();
+
+  /**
+   * @copydoc Dali::RenderSurface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization );
+
+  /**
+   * @copydoc Dali::RenderSurface::ReleaseLock()
+   */
+  virtual void ReleaseLock();
+
+protected:
+
+  /**
+   * Create XWindow
+   */
+  virtual void CreateXRenderable();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::ECore::EcoreXRenderSurface::UseExistingRenderable
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId );
+
+private: // Data
+
+  Ecore_X_Window   mX11Window; ///< X-Window
+  bool             mNeedToApproveDeiconify; ///< Whether need to send ECORE_X_ATOM_E_DEICONIFY_APPROVE event
+  std::string      mClassName;          ///< The class name of the window
+
+}; // class WindowRenderSurface
+
+} // namespace ECore
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_ECORE_X_WINDOW_RENDER_SURFACE_H__
diff --git a/adaptors/x11/x-event-handler.cpp b/adaptors/x11/x-event-handler.cpp
new file mode 100644 (file)
index 0000000..b8cb525
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <events/event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <uv.h>
+#include <Ecore_X.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+
+#include <cstring>
+
+#include <sys/time.h>
+
+#ifndef DALI_PROFILE_UBUNTU
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif // DALI_PROFILE_UBUNTU
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <x-events/x-event-manager.h>
+#include <events/gesture-manager.h>
+#include <window-render-surface.h>
+#include <clipboard-impl.h>
+#include <key-impl.h>
+#include <physical-keyboard-impl.h>
+#include <style-monitor-impl.h>
+#include <base/core-event-interface.h>
+#include <base/interfaces/window-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
+} // unnamed namespace
+#endif
+
+
+namespace
+{
+
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+const unsigned int BYTES_PER_CHARACTER_FOR_ATTRIBUTES = 3;
+
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+} // unnamed namespace
+
+
+struct EventHandler::Impl : public WindowEventInterface
+{
+  // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  Impl( EventHandler* handler, XID window, Display* display )
+  : mXEventManager(window, display, this),
+    mHandler( handler ),
+    mPaused( false )
+  {
+    mXEventManager.Initialize();
+  }
+  /**
+   * Destructor
+   */
+  ~Impl()
+  {
+  }
+  // @todo Consider allowing the EventHandler class to inherit from WindowEventInterface directly
+  virtual void TouchEvent( Dali::TouchPoint& point, unsigned long timeStamp )
+  {
+    mHandler->SendEvent( point, timeStamp );
+  }
+  virtual void KeyEvent( Dali::KeyEvent& keyEvent )
+  {
+    mHandler->SendEvent( keyEvent );
+  }
+  virtual void WheelEvent( Dali::WheelEvent& wheelEvent )
+  {
+    mHandler->SendWheelEvent( wheelEvent );
+  }
+  virtual void DamageEvent( Rect<int>& damageArea )
+  {
+    mHandler->SendEvent( damageArea );
+  }
+  virtual void WindowFocusOut( )
+  {
+    // used to do some work with ime
+  }
+  virtual void WindowFocusIn()
+  {
+    // used to do some work with ime
+  }
+
+  // Data
+  XEventManager mXEventManager;
+  EventHandler* mHandler;
+};
+
+EventHandler::EventHandler( RenderSurface* surface, CoreEventInterface& coreEventInterface, GestureManager& gestureManager, DamageObserver& damageObserver, DragAndDropDetectorPtr dndDetector )
+: mCoreEventInterface(coreEventInterface),
+  mGestureManager( gestureManager ),
+  mStyleMonitor( StyleMonitor::Get() ),
+  mDamageObserver( damageObserver ),
+  mRotationObserver( NULL ),
+  mDragAndDropDetector( dndDetector ),
+  mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
+  mClipboard(Clipboard::Get()),
+  mImpl( NULL )
+{
+  Ecore_X_Window window = 0;
+
+  // this code only works with the EcoreX11 RenderSurface so need to downcast
+  ECore::WindowRenderSurface* ecoreSurface = dynamic_cast< ECore::WindowRenderSurface* >( surface );
+  if( ecoreSurface )
+  {
+    window = ecoreSurface->GetXWindow();
+    Display* display = static_cast< Display* >(ecore_x_display_get());
+
+    mImpl = new Impl(this, window, display );
+
+  }
+
+}
+
+EventHandler::~EventHandler()
+{
+  if(mImpl)
+  {
+    delete mImpl;
+  }
+
+  mGestureManager.Stop();
+}
+
+void EventHandler::SendEvent(TouchPoint& point, unsigned long timeStamp)
+{
+  if(timeStamp < 1)
+  {
+    timeStamp = GetCurrentMilliSeconds();
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if(type != Integration::TouchEventCombiner::DispatchNone )
+  {
+    DALI_LOG_INFO(gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.deviceId, point.state, point.local.x, point.local.y);
+
+    // First the touch and/or hover event & related gesture events are queued
+    if(type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( touchEvent );
+      mGestureManager.SendEvent(touchEvent);
+    }
+
+    if(type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth)
+    {
+      mCoreEventInterface.QueueCoreEvent( hoverEvent );
+    }
+
+    // Next the events are processed with a single call into Core
+    mCoreEventInterface.ProcessCoreEvents();
+  }
+}
+
+void EventHandler::SendEvent(KeyEvent& keyEvent)
+{
+  Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
+  if ( physicalKeyboard )
+  {
+    if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ) )
+    {
+      GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
+    }
+  }
+
+  // Create KeyEvent and send to Core.
+  Integration::KeyEvent event(keyEvent.keyPressedName, keyEvent.keyPressed, keyEvent.keyCode,
+  keyEvent.keyModifier, keyEvent.time, static_cast<Integration::KeyEvent::State>(keyEvent.state));
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendWheelEvent( WheelEvent& wheelEvent )
+{
+  // Create WheelEvent and send to Core.
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::SendEvent( StyleChange::Type styleChange )
+{
+  DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
+  GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
+}
+
+void EventHandler::SendEvent( const DamageArea& area )
+{
+  mDamageObserver.OnDamaged( area );
+}
+
+void EventHandler::SendRotationPrepareEvent( const RotationEvent& event )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationPrepare( event );
+  }
+}
+
+void EventHandler::SendRotationRequestEvent( )
+{
+  if( mRotationObserver != NULL )
+  {
+    mRotationObserver->OnRotationRequest( );
+  }
+}
+
+void EventHandler::FeedTouchPoint( TouchPoint& point, int timeStamp)
+{
+  SendEvent(point, timeStamp);
+}
+
+void EventHandler::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  SendWheelEvent( wheelEvent );
+}
+
+void EventHandler::FeedKeyEvent( KeyEvent& event )
+{
+  SendEvent( event );
+}
+
+void EventHandler::FeedEvent( Integration::Event& event )
+{
+  mCoreEventInterface.QueueCoreEvent( event );
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Reset()
+{
+  mCombiner.Reset();
+
+  // Any touch listeners should be told of the interruption.
+  Integration::TouchEvent event;
+  TouchPoint point(0, TouchPoint::Interrupted, 0, 0);
+  event.AddPoint( point );
+
+  // First the touch event & related gesture events are queued
+  mCoreEventInterface.QueueCoreEvent( event );
+  mGestureManager.SendEvent( event );
+
+  // Next the events are processed with a single call into Core
+  mCoreEventInterface.ProcessCoreEvents();
+}
+
+void EventHandler::Pause()
+{
+  mPaused = true;
+  Reset();
+}
+
+void EventHandler::Resume()
+{
+  mPaused = false;
+  Reset();
+}
+
+void EventHandler::SetDragAndDropDetector( DragAndDropDetectorPtr detector )
+{
+  mDragAndDropDetector = detector;
+}
+
+void EventHandler::SetRotationObserver( RotationObserver* observer )
+{
+  mRotationObserver = observer;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/adaptors/x11/x-events/debug/x-input2-debug.cpp b/adaptors/x11/x-events/debug/x-input2-debug.cpp
new file mode 100644 (file)
index 0000000..8191e81
--- /dev/null
@@ -0,0 +1,289 @@
+ // EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+
+#ifdef DEBUG_ENABLED
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <ostream>
+#include <iomanip>
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace X11Debug
+{
+
+#ifdef DEBUG_ENABLED
+
+namespace
+{
+
+
+Integration::Log::Filter* gInputDeviceLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_INPUT_DEVICES");
+Integration::Log::Filter* gInputEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_INPUT_EVENTS");
+
+struct XNameId
+{
+  const char* const name;
+  int id;
+};
+
+const XNameId eventTable[]=
+{
+    { "XI_KeyPress"        ,XI_KeyPress         },
+    { "XI_KeyRelease"      ,XI_KeyRelease       },
+    { "XI_ButtonPress"     ,XI_ButtonPress      },
+    { "XI_ButtonRelease"   ,XI_ButtonRelease    },
+    { "XI_Motion"          ,XI_Motion           },
+    { "XI_Enter"           ,XI_Enter            },
+    { "XI_Leave"           ,XI_Leave            },
+    { "XI_FocusIn"         ,XI_FocusIn          },
+    { "XI_FocusOut"        ,XI_FocusOut         },
+    { "XI_HierarchyChanged",XI_HierarchyChanged },
+    { "XI_PropertyEvent"   ,XI_PropertyEvent    },
+    { "XI_RawKeyPress"     ,XI_RawKeyPress      },
+    { "XI_RawKeyRelease"   ,XI_RawKeyRelease    },
+    { "XI_RawButtonPress"  ,XI_RawButtonPress   },
+    { "XI_RawButtonRelease",XI_RawButtonRelease },
+    { "XI_RawMotion"       ,XI_RawMotion        },
+    { "XI_TouchBegin"      ,XI_TouchBegin       },
+    { "XI_TouchUpdate"     ,XI_TouchUpdate      },
+    { "XI_TouchEnd"        ,XI_TouchEnd         },
+    { "XI_TouchOwnership"  ,XI_TouchOwnership   },
+    { "XI_RawTouchBegin"   ,XI_RawTouchBegin    },
+    { "XI_RawTouchUpdate"  ,XI_RawTouchUpdate   },
+    { "XI_RawTouchEnd"     ,XI_RawTouchEnd      }
+};
+
+const XNameId deviceTypeTable[]=
+{
+    { "Master Pointer "    ,XIMasterPointer     },
+    { "Master Keyboard"    ,XIMasterKeyboard    },
+    { "Slave Pointer  "    ,XISlavePointer      },
+    { "Slave Keyboard "    ,XISlaveKeyboard     },
+    { "Floating Slave "    ,XIFloatingSlave     }
+};
+
+const XNameId inputClassTable[]=
+{
+    { "Key"      ,XIKeyClass       },
+    { "Button"   ,XIButtonClass    },
+    { "Valuator" ,XIValuatorClass  },
+    { "Scroll"   ,XIScrollClass    },
+    { "Touch"    ,XITouchClass     }
+};
+
+const unsigned int numberEvents = sizeof( eventTable ) / sizeof( eventTable[0] );
+const unsigned int numberDevices = sizeof( deviceTypeTable ) / sizeof( deviceTypeTable[0] );
+const unsigned int numberInputClasses = sizeof( inputClassTable ) / sizeof( inputClassTable[0] );
+
+const char* GetEventName( int eventId )
+{
+  for( unsigned int i = 0; i < numberEvents; ++i )
+  {
+    if( eventTable[i].id == eventId )
+    {
+      return eventTable[i].name;
+    }
+  }
+  return "unknown event";
+}
+const char* GetDeviceHierachyName( int deviceType )
+{
+  for( unsigned int i = 0; i < numberDevices; ++i )
+  {
+    if( deviceTypeTable[i].id == deviceType )
+    {
+      return deviceTypeTable[i].name;
+    }
+  }
+  return "unknown device";
+}
+const char* GetInputClassName( int classId )
+{
+  for( unsigned int i = 0; i < numberInputClasses; ++i )
+  {
+    if( inputClassTable[i].id == classId )
+    {
+      return inputClassTable[i].name;
+    }
+  }
+  return "unknown input class name";
+}
+
+std::string GetInputDeviceInfo( const XIDeviceInfo* device, bool master )
+{
+  // formatted output similar to xinput -list except it includes class + source information
+  int startWidth = 45;
+
+  std::string slavePadding="  ↳ ";
+  if( master )
+  {
+    // slave entries are shifted to the right
+    startWidth += 4;
+    slavePadding="";
+  }
+
+  std::ostringstream oss;
+  oss << "⎜" << slavePadding << std::setw(startWidth) <<  std::left << device->name ;
+  oss << std::setw(1) << " id= " << std::setw(1) << device->deviceid ;
+  oss << "\t[" << GetDeviceHierachyName( device->use ) << " ("<< device->attachment << ") ]";
+  oss << std::setw(1) << "\t Classes: ";
+
+  for( int n = 0; n < device->num_classes; ++n )
+  {
+    XIAnyClassInfo *classInfo = device->classes[n];
+    oss << GetInputClassName( classInfo->type ) << ", source ( "<< classInfo->sourceid << ")";
+  }
+  oss << "\n";
+
+  return oss.str();
+}
+
+
+}// unanmed namespace
+
+void LogInputDeviceInfo( const XIDeviceInfo* devices, unsigned int numberOfDevices )
+{
+  // early exit if the filter is not enabled in debug mode
+  if( ! gInputDeviceLogFilter->IsEnabledFor( Debug::General ) )
+  {
+    return;
+  }
+
+  const XIDeviceInfo* device = devices;
+  const  XIDeviceInfo* masterKeyboard = NULL;
+  const XIDeviceInfo* masterPointer  = NULL;
+  Dali::Vector< const XIDeviceInfo* > slaveKeyboards;
+  Dali::Vector< const XIDeviceInfo* > slavePointers;
+  Dali::Vector< const XIDeviceInfo* > floatingSlaves;
+
+  // go through the device list and sort by type
+  for( unsigned int i = 0; i < numberOfDevices; ++i, ++device )
+  {
+    switch( device->use )
+    {
+      case XIMasterPointer:
+      {
+        masterPointer = device;
+        break;
+      }
+      case XIMasterKeyboard:
+      {
+        masterKeyboard = device;
+        break;
+      }
+      case XISlavePointer:
+      {
+        slavePointers.PushBack( device );
+        break;
+      }
+      case XISlaveKeyboard:
+      {
+        slaveKeyboards.PushBack( device );
+        break;
+      }
+      case XIFloatingSlave:
+      {
+        floatingSlaves.PushBack( device );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  std::ostringstream oss;
+
+  oss << "\n" << GetInputDeviceInfo( masterKeyboard , true);
+  for( VectorBase::SizeType i = 0; i < slaveKeyboards.Count(); ++i )
+  {
+    oss << GetInputDeviceInfo( slaveKeyboards[i], false );
+  }
+  oss <<  "\n" << GetInputDeviceInfo( masterPointer, true );
+  for( VectorBase::SizeType i = 0; i < slavePointers.Count(); ++i )
+  {
+    oss << GetInputDeviceInfo( slavePointers[i], false);
+  }
+  for( VectorBase::SizeType i = 0; i < floatingSlaves.Count(); ++i )
+  {
+    oss <<  GetInputDeviceInfo( floatingSlaves[i], false );
+  }
+
+ // DALI_LOG_ERROR_NOFN( "%s \n",oss.str().c_str() );
+  DALI_LOG_INFO( gInputDeviceLogFilter, Debug::General, "%s\n", oss.str().c_str() );
+}
+
+void LogXI2Event( XGenericEventCookie* cookie )
+{
+  // early exit if the filter is not enabled
+  if( ! gInputEventLogFilter->IsEnabledFor( Debug::General ) )
+  {
+    return;
+  }
+
+  std::ostringstream oss;
+  oss << "XI2 event:" << GetEventName( cookie->evtype );
+
+  XIDeviceEvent *event = static_cast< XIDeviceEvent* >(cookie->data);
+
+  oss << ", device_id("<< event->deviceid << ")  source_id( "<< event->sourceid << ")" << ", flags: " << event->flags;
+  oss << ", root-window: " << event->root << ", event-window: "<< event->event << ", child-window:" << event->child;
+  if( cookie->evtype == XI_KeyPress)
+  {
+    oss << "base " << event->mods.base << "latched " << event->mods.latched;
+    oss << "locked " << event->mods.locked << "effective " << event->mods.effective;
+
+    if(  event->mods.effective & ShiftMask) oss << "Shift";
+    if(  event->mods.effective & LockMask) oss << "LockMask"; // caps lock
+    if(  event->mods.effective & ControlMask) oss << "ControlMask";
+    if(  event->mods.effective & Mod1Mask) oss << "Mod1Mask";  // alt
+    if(  event->mods.effective & Mod2Mask) oss << "Mod2Mask";  // num lock
+    if(  event->mods.effective & Mod3Mask) oss << "Mod3Mask";
+    if(  event->mods.effective & Mod4Mask) oss << "Mod4Mask";  // WINDOWS
+    if(  event->mods.effective & Mod5Mask) oss << "Mod5Mask";  // Alt gr
+
+  }
+
+   // Mouse button state
+  oss << " button state\n";
+  for( int i =0; i< event->buttons.mask_len ; i++)
+  {
+    oss << "," << int(event->buttons.mask[i]);
+  }
+
+ // DALI_LOG_ERROR_NOFN( "%s \n",oss.str().c_str() );
+  DALI_LOG_INFO( gInputEventLogFilter, Debug::General, "%s\n", oss.str().c_str() );
+
+}
+
+
+
+#else
+
+void LogDeviceInfo( Display* display, XIDeviceInfo* device )
+{
+}
+void LogXI2Event( XGenericEventCookie* cookie )
+{
+}
+
+#endif
+
+
+} // X11 Debug
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/x11/x-events/debug/x-input2-debug.h b/adaptors/x11/x-events/debug/x-input2-debug.h
new file mode 100644 (file)
index 0000000..cbabe68
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __DALI_INTERNAL_X_INPUT_2_DEBUG_H__
+#define __DALI_INTERNAL_X_INPUT_2_DEBUG_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace X11Debug
+{
+
+/**
+ * To log input devices found on the system buid DALi in debug mode.
+ * Then on the command line:
+ *
+ * export LOG_X_INPUT_DEVICES=2
+ * dali-demo
+ *
+ *
+ * To log XInput events
+ *
+ * export LOG_X_INPUT_EVENTS=2
+ * dali-demo
+ *
+ * 2 = LogLevel::General
+ */
+
+
+/**
+ * @brief Debug log input device information.
+ * Similar output to command line tool 'xinput -list' except it includes class + source information
+ * Useful if the device doesn't have xinput tool installed
+ * @param devices array of XIDeviceInfo
+ * @param numberOfDevices number of devices
+ */
+void LogInputDeviceInfo( const XIDeviceInfo* devices, unsigned int numberOfDevices );
+
+/**
+ * @brief Debug log input event information.
+ * @param cookie input event cookie
+ */
+void LogXI2Event( XGenericEventCookie* cookie );
+
+} // X11 Debug
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
diff --git a/adaptors/x11/x-events/x-event-manager.cpp b/adaptors/x11/x-events/x-event-manager.cpp
new file mode 100644 (file)
index 0000000..36ab25d
--- /dev/null
@@ -0,0 +1,86 @@
+// CLASS HEADER
+#include "x-event-manager.h"
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <cstring>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+//Dali::Integration::Log::Filter* gInputDeviceLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_X_EVENT");
+#endif
+
+}
+
+XEventManager::XEventManager( XID window, Display* display, WindowEventInterface* eventInterface )
+: mXInput2( window, display, eventInterface ),
+  mFileDescriptorMonitor( NULL ),
+  mDisplay( display ),
+  mWindow( window ),
+  mInitialized( false )
+{
+
+}
+XEventManager::~XEventManager()
+{
+  delete mFileDescriptorMonitor;
+}
+
+void XEventManager::Initialize()
+{
+  if( mInitialized )
+  {
+    return;
+  }
+
+  mXInput2.Initialize();
+
+  // Start monitoring for X events on a file descriptor return via ConnectionNumber.
+  int fileDescriptor = ConnectionNumber( mDisplay );
+
+  CallbackBase* callback =  MakeCallback( this, &XEventManager::XEventReceived);
+
+  mFileDescriptorMonitor = new FileDescriptorMonitor( fileDescriptor, callback );
+
+  mInitialized = true;
+}
+
+
+void XEventManager::XEventReceived()
+{
+  while( XPending( mDisplay) )
+  {
+    XEvent xEvent;
+    XNextEvent( mDisplay, &xEvent );
+
+    // cookie data pointer is undefined until XGetEventData is called.
+    XGenericEventCookie* cookie = &xEvent.xcookie;
+
+    if (XGetEventData( mDisplay, cookie))
+    {
+      if( cookie->extension == mXInput2.GetExtensionId() )
+      {
+        mXInput2.ProcessEvent( cookie );
+      }
+      XFreeEventData( mDisplay, cookie );
+    }
+  }
+}
+
+
+} // namespace internal
+} // namespace adaptor
+} // namespace dali
diff --git a/adaptors/x11/x-events/x-event-manager.h b/adaptors/x11/x-events/x-event-manager.h
new file mode 100644 (file)
index 0000000..d4dd963
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef __DALI_INTERNAL_X_EVENT_MANAGER_H__
+#define __DALI_INTERNAL_X_EVENT_MANAGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <file-descriptor-monitor.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/window-event-interface.h>
+#include "x-input2.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *
+ * @brief Used to handle X events.
+ * The code is mainloop agnostic, so the monitoring of the X event file descriptor
+ * for X events is external to this class.
+ *
+ */
+class XEventManager
+{
+
+public:
+
+  /**
+   * Constructor
+   * @param[in] window ID
+   * @param[in] display x-connection
+   * @param[in] eventInterface window event interface
+   */
+  XEventManager( XID window, Display* display, WindowEventInterface* eventInterface );
+
+  /**
+   * @brief non virtual destructor
+   */
+  ~XEventManager();
+
+  /**
+   * @brief Initialize
+   */
+  void Initialize();
+
+private:
+
+  /**
+   * @brief Should be called when the Event file descriptor signals data is available
+   */
+  void XEventReceived();
+
+  // Undefined copy constructor.
+  XEventManager( const XEventManager& );
+
+  // Undefined assignment operator.
+  XEventManager& operator=( const XEventManager& );
+
+private:
+
+  XInput2 mXInput2;                                       ///< XInput2 handler
+  FileDescriptorMonitor* mFileDescriptorMonitor;          ///< File descriptor monitor for X events
+  Display* mDisplay;                                      ///< X connection
+  XID mWindow;                                            ///< Window to receive events for
+  bool mInitialized:1;
+
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_X_EVENT_MANAGER_H__
diff --git a/adaptors/x11/x-events/x-input2-device.cpp b/adaptors/x11/x-events/x-input2-device.cpp
new file mode 100644 (file)
index 0000000..a1b4ede
--- /dev/null
@@ -0,0 +1,66 @@
+//CLASS HEADER
+#include "x-input2-device.h"
+
+// EXTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void XInput2Device::AssignDeviceInfo( const XIDeviceInfo* device )
+{
+  deviceId = device->deviceid;
+  attachment = device->attachment;
+  use = device->use;
+
+  for( int n = 0; n < device->num_classes; ++n )
+  {
+    XIAnyClassInfo *classInfo = device->classes[n];
+    switch( classInfo->type  )
+    {
+      case XITouchClass:
+      {
+        touchClass = true;
+        break;
+      }
+      case XIButtonClass:
+      {
+        buttonClass = true;
+        break;
+      }
+      case XIValuatorClass:
+      {
+        valuatorClass = true;
+        break;
+      }
+      case XIScrollClass:
+      {
+        scrollClass = true;
+        break;
+      }
+      case XIKeyClass:
+      {
+        keyClass = true;
+        break;
+      }
+      default:
+      {
+        // unknown
+        break;
+      }
+    }
+  }
+
+
+}
+
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/adaptors/x11/x-events/x-input2-device.h b/adaptors/x11/x-events/x-input2-device.h
new file mode 100644 (file)
index 0000000..59d0e52
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef __DALI_INTERNAL_X_INPUT2_DEVICE_H__
+#define __DALI_INTERNAL_X_INPUT2_DEVICE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <X11/extensions/XInput2.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief struct used to encpasulate XIDeviceInfo information.
+ * Kept as a POD so it can be used in a Dali::Vector
+ */
+struct XInput2Device
+{
+  /**
+   * @brief constructor
+   */
+  XInput2Device()
+  : deviceId(0),
+  attachment(0),
+  use(0),
+  keyClass(false),
+  touchClass(false),
+  buttonClass(false),
+  valuatorClass(false),
+  scrollClass(false)
+  {}
+
+  /**
+   * Assign device information to the object
+   */
+  void AssignDeviceInfo( const XIDeviceInfo* device );
+
+  int deviceId;           ///< X device ID
+  int attachment;         ///< see XI2 DEVICEINFO struct for details
+  int use;                ///< see XI2 DEVICEINFO struct for details
+  bool keyClass:1;        ///< device supports key input
+  bool touchClass:1;      ///< device supports touch input
+  bool buttonClass:1;     ///< device supports button input
+  bool valuatorClass:1;   ///< device supports an axis, e.g. mouse axis, tablet pen tilt angle..
+  bool scrollClass:1;     ///< device supports scroll
+
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
diff --git a/adaptors/x11/x-events/x-input2.cpp b/adaptors/x11/x-events/x-input2.cpp
new file mode 100644 (file)
index 0000000..b965609
--- /dev/null
@@ -0,0 +1,315 @@
+// CLASS HEADER
+#include "x-input2.h"
+
+// EXTERNAL INCLUDES
+#include <X11/XKBlib.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include "debug/x-input2-debug.h"
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// For multi-touch we need XI2 version 2.2
+int XI2MinorVersionRequired = 2;
+int XI2MajorVersionRequired = 2;
+}
+
+XInput2::XInput2( XID window, Display* display, WindowEventInterface* eventInterface )
+: mEventInterface( eventInterface ),
+  mDisplay( display ),
+  mWindow( window ),
+  mXI2ExtensionId(-1),
+  mMultiTouchSupport( false )
+{
+
+}
+XInput2::~XInput2()
+{
+}
+
+void XInput2::Initialize()
+{
+  // Check if X supports the multi-touch protocol
+  QueryMultiTouchSupport();
+
+  // Query what input devices are available on the system.
+  QueryDevices();
+
+  // Select the input events we want to receive from the input devices available
+  SelectInputEvents();
+
+}
+
+int XInput2::GetExtensionId() const
+{
+  return mXI2ExtensionId;
+}
+
+bool XInput2::FilteredDevice( int deviceId ) const
+{
+  for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
+  {
+    if( mInputDeviceInfo[i].deviceId == deviceId )
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool XInput2::PreProcessEvent( XIDeviceEvent *deviceEvent ) const
+{
+  // @todo need to do some testing to see if this check is actually required
+  // E.g. if IME window is sending events, this check may fail
+  if( deviceEvent->event != mWindow )
+  {
+    return false;
+  }
+  // emulated flags means that the event has been emulated from another XI 2.x event for legacy client support
+  // We don't call XISelectEvents on these events so hopefully shouldn't get them.
+  if( ( deviceEvent->flags & XIPointerEmulated ) || ( deviceEvent->flags & XITouchEmulatingPointer ) )
+  {
+    return false;
+  }
+
+  if( !FilteredDevice( deviceEvent->deviceid ))
+  {
+    return false;
+  }
+  return true;
+}
+
+void XInput2::CreateKeyEvent( const XIDeviceEvent* deviceEvent, KeyEvent& keyEvent ) const
+{
+  // get the physical key code ( range 8..255)
+  KeyCode keycode = deviceEvent->detail;
+
+  keyEvent.keyCode = keycode;
+  keyEvent.state = KeyEvent::Down;
+  keyEvent.keyModifier = deviceEvent->mods.effective;
+
+  // extract key symbol. The symbol is typically the name visible on the key
+  // e.g. key code 201 might = Brightness increase, or a Korean character depending on the keyboard mapping.
+  // @todo For XKbKeycodeToKeysym to work correctly we need the group and level.
+  // investigate using XkbGetState to get initial state then start monitoring for XkbStateNotify events
+  KeySym sym = XkbKeycodeToKeysym( mDisplay, keycode, 0 /* group */ , keyEvent.IsShiftModifier() );
+  char* keyname = XKeysymToString( sym );
+
+  keyEvent.keyPressedName = keyname;
+  keyEvent.time = deviceEvent->time;
+
+}
+
+void XInput2::ProcessEvent( XGenericEventCookie* cookie )
+{
+  XIDeviceEvent* deviceEvent = static_cast< XIDeviceEvent* >(cookie->data);
+
+  X11Debug::LogXI2Event( cookie );
+
+  bool requiresProcessing  = PreProcessEvent( deviceEvent );
+
+  if( ! requiresProcessing )
+  {
+    return;
+  }
+
+  TouchPoint point ( deviceEvent->deviceid, TouchPoint::Last, deviceEvent->event_x, deviceEvent->event_y );
+  Time time( deviceEvent->time ); // X is using uint32 for time field ( see XI2proto.h )
+
+  switch( cookie->evtype)
+  {
+    case XI_TouchUpdate:
+    case XI_Motion:
+    {
+      point.state = TouchPoint::Motion;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_TouchBegin:
+    case XI_ButtonPress:
+    {
+      point.state = TouchPoint::Down;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_TouchEnd:
+    case XI_ButtonRelease:
+    {
+      point.state = TouchPoint::Up;
+      mEventInterface->TouchEvent( point, time );
+      break;
+    }
+    case XI_FocusIn:
+    {
+      mEventInterface->WindowFocusIn();
+      break;
+    }
+    case XI_FocusOut:
+    {
+      mEventInterface->WindowFocusOut();
+      break;
+    }
+    case XI_KeyPress:
+    {
+      KeyEvent keyEvent;
+      CreateKeyEvent( deviceEvent, keyEvent );
+      mEventInterface->KeyEvent( keyEvent );
+      break;
+    }
+    default:
+    {
+      break;
+    }
+  }
+}
+
+void XInput2::QueryMultiTouchSupport()
+{
+  int minor = XI2MinorVersionRequired;
+  int major = XI2MajorVersionRequired;
+  int firstEventCode, firstErrorCode;
+
+  // Check if the extension is available and get the extension id
+  if( !XQueryExtension(mDisplay, "XInputExtension",  &mXI2ExtensionId, &firstEventCode, &firstErrorCode) )
+  {
+    DALI_LOG_ERROR(" XInputExtension not available \n");
+    return;
+  }
+
+  // inform X that DALi ( the client ) supports XI2 version 2.2
+  // it will assign the X servers supported version to the parameters
+  int ret = XIQueryVersion( mDisplay, &major, &minor);
+  if( ret == BadValue )
+  {
+    DALI_LOG_ERROR(" XIQueryVersion %d,%d failed \n", major, minor );
+    return;
+  }
+
+  // check the version is supports multi-touch
+  if( ( major * 1000 + minor ) >= ( XI2MajorVersionRequired * 1000 + XI2MinorVersionRequired ) )
+  {
+      mMultiTouchSupport = true;
+  }
+  else
+  {
+    DALI_LOG_ERROR( "XInput 2.2 or greater required for multi-touch\n");
+  }
+
+}
+void XInput2::QueryDevices()
+ {
+   int numberOfDevices( 0 );
+
+   // QueryDevice returns information about one or more input devices
+   XIDeviceInfo* deviceInfoArray = XIQueryDevice( mDisplay, XIAllDevices, &numberOfDevices);
+   XIDeviceInfo* device = deviceInfoArray;
+
+   X11Debug::LogInputDeviceInfo( deviceInfoArray, numberOfDevices );
+
+   mInputDeviceInfo.Resize( numberOfDevices );
+
+   for( int i = 0; i < numberOfDevices; ++i, ++device )
+   {
+     XInput2Device info;
+
+     info.AssignDeviceInfo( device );
+
+     mInputDeviceInfo.PushBack( info );
+   }
+
+   XIFreeDeviceInfo( deviceInfoArray );
+ }
+
+void XInput2::SelectEvents( int deviceId, const Dali::Vector< unsigned int >& filter )
+{
+  if( filter.Size() ==  0)
+  {
+    return;
+  }
+
+  // each event like XI_ButtonPress is stored as unique bit, so if there's 32 events we need 4 bytes
+  // the XIMaskLen macro provides the length for us at compile time.
+  unsigned char mask[ XIMaskLen( XI_LASTEVENT ) ] = {};
+  XIEventMask eventMask;
+
+  eventMask.deviceid = deviceId;
+  eventMask.mask_len = sizeof( mask);
+  eventMask.mask = mask;
+
+  for( VectorBase::SizeType i = 0; i< filter.Count(); ++i )
+  {
+      XISetMask( mask, filter[i] );
+  }
+
+  XISelectEvents( mDisplay, mWindow, &eventMask, 1);
+
+}
+void XInput2::SelectInputEvents()
+{
+  /*
+   * From the X documentation:
+   * "A master pointer is a virtual pointer device that does not represent a physical device.
+   * If a slave device generates an event, the event is also generated by the respective master device.
+   * Multiple slave devices can be attached to a single master device."
+   * master = cursor / keyboard focus,
+   * slave = physical device
+   *
+   * For motion events, we currently just listen to the slave devices. This allows us the ability to
+   * perform a XIGrabDevice on the slave if we need to, which will temporarily detach it from the master.
+   * In DALi we currently don't perform a grab as typically we just have a single x-window displayed.
+   * Where as other toolkits may have a window for a popup and want do know when the mouse is clicked outside
+   * of the popup, to close it.
+   */
+  Dali::Vector< unsigned int > eventFilter;
+  eventFilter.Reserve( 6 );    // typically filter no more than 6 events
+
+  for( VectorBase::SizeType i = 0; i < mInputDeviceInfo.Count(); ++i )
+  {
+    const XInput2Device& device( mInputDeviceInfo[ i ] );
+
+    eventFilter.Clear();
+
+    if( ( device.use == XIFloatingSlave ) || ( device.use == XISlavePointer ))
+    {
+      if( device.buttonClass )
+      {
+        eventFilter.PushBack( XI_ButtonPress );
+        eventFilter.PushBack( XI_ButtonRelease );
+        eventFilter.PushBack( XI_Motion );
+      }
+      if( device.touchClass )
+      {
+        eventFilter.PushBack( XI_TouchUpdate );
+        eventFilter.PushBack( XI_TouchBegin );
+        eventFilter.PushBack( XI_TouchEnd );
+      }
+      SelectEvents( device.deviceId, eventFilter );
+    }
+    // @todo work out if we should just be listening to MasterKeyboard
+    else if( device.use == XISlaveKeyboard )
+    {
+      if( device.keyClass )
+      {
+        eventFilter.PushBack( XI_KeyPress );
+        eventFilter.PushBack( XI_KeyRelease );
+
+        SelectEvents( device.deviceId, eventFilter );
+      }
+
+    }
+  }
+}
+} // namespace internal
+} // namespace adaptor
+} // namespace dali
diff --git a/adaptors/x11/x-events/x-input2.h b/adaptors/x11/x-events/x-input2.h
new file mode 100644 (file)
index 0000000..abc3f5b
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef __DALI_INTERNAL_X_INPUT_2_MANAGER_H__
+#define __DALI_INTERNAL_X_INPUT_2_MANAGER_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI2.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <base/interfaces/window-event-interface.h>
+#include "x-input2-device.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *
+ * @brief Used to setup and process XInput2 events.
+ *
+ * For help with debugging, build DALi in debug mode then set the environment variables
+ * export LOG_X_INPUT_EVENTS=2
+ * export LOG_X_INPUT_DEVICES=2
+ */
+class XInput2
+{
+
+public:
+
+  /**
+   * @brief Constructor
+   */
+  XInput2( XID window, Display* display, WindowEventInterface* eventInterface );
+
+  /**
+   * @brief destructor
+   */
+  ~XInput2();
+
+  /**
+   * @brief enumerates input devices using XIQueryDevice then sets up event filtering using XISelectEvents
+   */
+  void Initialize();
+
+  /**
+   * @brief get X the extension id
+   * @return the Id
+   */
+  int GetExtensionId() const;
+
+  /**
+   * @brief process an XInput2 event
+   * @param cookie X cookie
+   */
+  void ProcessEvent( XGenericEventCookie* cookie );
+
+
+private:
+
+  /**
+   * @brief query x input devices
+   */
+  void QueryDevices();
+
+  /**
+   * @brief query multi-touch support
+   */
+  void QueryMultiTouchSupport();
+
+  /**
+   * Uses XISelectEvents to select the events we want to recieve from each input device
+   */
+  void SelectInputEvents();
+
+  /**
+   * @brief checks if we are filtering events from a specific device
+   * @param[in] deviceId device id
+   * @return true if the device is being filtered
+   */
+  bool FilteredDevice( int deviceId ) const;
+
+  /**
+   * @brief Select specific events to be filtered on a device
+   * @param[in] device id
+   * @param[in] filter vector of X input events like XI_ButtonPress
+   */
+  void SelectEvents( int deviceId, const Dali::Vector< unsigned int >& filter );
+
+  /**
+   * @brief checks if the event should be processed
+   * @param[in] deviceEvent device event
+   * @return true if should be processed
+   */
+  bool PreProcessEvent( XIDeviceEvent *deviceEvent ) const;
+
+  /**
+   * @brief creates a DALi key event given a XIDeviceEvent for a key press
+   * @param[in] deviceEvent device event
+   * @param[out] keyEvent DALi key event
+   */
+  void CreateKeyEvent( const XIDeviceEvent* deviceEvent, KeyEvent& keyEvent ) const;
+
+private:
+
+  Dali::Vector< XInput2Device > mInputDeviceInfo;   ///< list of input devices
+  WindowEventInterface* mEventInterface;            ///< window event interface
+  Display* mDisplay;                                ///< X display
+  XID mWindow;                                      ///< X window
+  int mXI2ExtensionId;                              ///< XI2 extension id
+  bool mMultiTouchSupport:1;                        ///< whether multi-touch is supported
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif
diff --git a/automated-tests/.gitignore b/automated-tests/.gitignore
new file mode 100644 (file)
index 0000000..34dc85b
--- /dev/null
@@ -0,0 +1,5 @@
+*.xml
+build
+build.log
+tct*core.h
+results_xml.*
\ No newline at end of file
diff --git a/automated-tests/.gitignore-with-autogenerated-files b/automated-tests/.gitignore-with-autogenerated-files
new file mode 100644 (file)
index 0000000..f039d8a
--- /dev/null
@@ -0,0 +1,4 @@
+*.xml
+build
+build.log
+tct*core.h
diff --git a/automated-tests/.gitignore-without-autogenerated-files b/automated-tests/.gitignore-without-autogenerated-files
new file mode 100644 (file)
index 0000000..8f3f9e2
--- /dev/null
@@ -0,0 +1,3 @@
+*.xml
+build
+build.log
diff --git a/automated-tests/CMakeLists.txt b/automated-tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e15203
--- /dev/null
@@ -0,0 +1,11 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(tct_coreapi_utc)
+
+INCLUDE(FindPkgConfig)
+SET(BIN_DIR "/opt/usr/bin")
+
+INCLUDE_DIRECTORIES(
+       src/common
+)
+
+ADD_SUBDIRECTORY(src)
diff --git a/automated-tests/README.md b/automated-tests/README.md
new file mode 100644 (file)
index 0000000..063b543
--- /dev/null
@@ -0,0 +1,214 @@
+Testing environment   {#auto_testing}
+===================
+
+The new test environment from Tizen is the Web-TCT test suite. This was written for testing web components, but can easily be used for testing Dali.
+
+Each of the DALi repositories, **dali-core**, **dali-adaptor** and **dali-toolkit**, have their own test suites under the `automated-tests` folder. Within the src folder are a number of secondary folders - these correspond to 'API' tests  and internal (for desktop testing only)
+
+Installation
+------------
+
+There are usage instructions and installation instructions on the Tizen.org website [here](http://download.tizen.org/tct/2.2.1/Manual/Web_TCT_2.2.1_User_Guide_v1.0.pdf)
+
+These are device specific instructions, however, installing the test suite will also provide the relevant packages for running tests on Ubuntu ( follow the first block of quickstart instructions below ).
+
+If you are planning on running tests on device, then flash your handset with latest image, or turn off ssh: `set_usb_debug.sh --mtp-sdb` and plug it in, then follow the quickstart instructions repeated below.
+
+Quickstart
+----------
+
+For target or desktop testing:
+
+    cd ~/Packages
+    wget http://download.tizen.org/tct/2.2.1/2.2.1_r1/web-tct_2.2.1_r1.tar.gz
+    sudo tar xzf web-tct_2.2.1_r1.tar.gz
+    cd web-tct_2.2.1_r1/tools
+    sudo -E ./tct-config-host.sh
+
+
+If you are planning on running tests on device, then plug in your freshly flashed device and run the following commands:
+
+    sudo apt-get install sdb
+    ./tct-config-device.sh
+
+**NOTE:** After flashing a handset, you will need to run this step of the installation again.
+
+Testing on desktop
+==================
+
+Building libraries with coverage options
+----------------------------------------
+
+Building dali adaptor:
+
+    cd dali-adaptor  # the location of your dali-adaptor repository
+    cd build/tizen
+    export CC=gcc
+    export CXX=g++
+    git clean -fxd . # Only do this in the build folder
+    autoreconf --install
+    CXXFLAGS='-g -O0 --coverage' LDFLAGS='--coverage' ./configure --prefix=$DESKTOP_PREFIX --enable-debug
+    make -j8 install
+
+Note, you __must__ use a local build and not a distributed build, and you __must__ also build with debug enabled to allow *DALI_ASSERT_DEBUG* to trigger on wrong behaviour ( Which should always be a test case failure! )
+
+Building the tests
+------------------
+
+Run the following commands:
+
+    cd automated-tests
+    ./build.sh
+
+This will build dali-adaptor, dali-adaptor-internal and dali-platform-abstraction test sets.
+
+Test sets can be built individually:
+
+    ./build.sh dali-adaptor
+
+They can also be built without regenerating test case scripts (Useful for quicker rebuilds)
+
+    ./build.sh -n dali-adaptor
+
+Or without cleaning down the build area (Useful for fast build/run/debug cycles)
+
+    ./build.sh -n -r dali-adaptor
+
+
+Executing the tests
+-------------------
+
+To execute tests, cd into automated-tests and run
+
+    ./execute.sh
+
+This will execute dali and dali-internal test sets. Note that the output summary for the first will be printed before running the second.
+
+By default the tests execute in parallel, which is faster but does not produce a single output file (summary.xml).  Use this to execute the tests in series:
+
+    ./execute.sh -s
+
+To see the summary.xml results, execute the tests in series and open as follows:
+
+    firefox --new-window summary.xml
+
+To see a list of all of the options:
+
+    ./execute.sh -h
+
+To execute a subset of tests, you can run individual test sets, e.g.
+
+    ./execute.sh dali-adaptor
+
+To get coverage output, run
+
+    ./coverage.sh
+
+
+Testing on target
+=================
+
+To build for target, first build and install dali-core, dali-adaptor and dali-toolkit, then build dali-capi without --keep-packs option.
+
+You will need to install libconfig-tiny-perl:
+
+sudo apt-get install libconfig-tiny-perl
+
+If you use a non-standard `GBS_ROOT` then you will need to edit the tcbuild script to match your configuration - change line 96 and add a -B option with your GBS-ROOT path (line 96 = `gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs` ).
+To install on device from a non-standard GBS_ROOT, also modify line 28 (`RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"`).
+
+For Dali Adaptor, cd into automated-tests, and use:
+
+    sudo ./tcbuild build dali-adaptor
+    sudo ./tcbuild build dali-adaptor-internal
+    sudo ./tcbuild build dali-platform-abstraction
+    ./tcbuild install dali-adaptor
+    ./tcbuild install dali-adaptor-internal
+    ./tcbuild install dali-platform-abstraction
+
+Ensure your handset's filesystem is writable:
+
+    sdb shell su -c "change-booting-mode.sh --update"
+
+To execute tests, cd into automated-tests and run
+
+    tct-mgr
+
+This will bring up the java test suite program. You should see the Plan pane with a list of all tests in. Select the tct-dali-core-tests. and you will be offered a dialog to choose a test plan: either create a new one or use temp.
+Select dali test suite, and click Run, then "Create a new plan", and call it "Dali-Core" or some such. It will now run the dali-test suite.
+
+You can find the output files under /opt/tct/manager/result/
+
+
+Adding tests
+============
+
+To Managed API
+--------------
+
+If you are adding test cases for new or existing managed API (CAPI), you need to add your changes to the src/dali mirror, and copy your change to the managed test suite in core-api. You need to inform HQ of your update.
+
+For internal API
+----------------
+
+If you are adding tests for internal API, then this will only work on desktop, and you should add your tests to the src/dali-adaptor-internal test suite.
+
+General
+-------
+
+If you are adding test cases to existing files, then all you need to do is create functions with the method signature
+
+    int UtcTestcase(void)
+    {
+      TestApplication application;
+      ...
+      END_TEST;
+    }
+
+
+Note that **there must be no extra whitespace in the method signature** (i.e., it must violate our coding convention and follow __exactly__ this pattern: `int UtcDaliMyTestcaseName(void)`), as it's parsed by an awk script to auto-generate the testcase arrays in the main header file.
+
+You can contine to use the TET api, e.g. `tet_infoline`, `tet_result` and our test check methods `DALI_TEST_CHECK`, `DALI_TEST_EQUALS`, etc.
+
+If you need any non-test methods or variables, ensure they are wrapped in an anonymous namespace.
+
+If you are adding new test files, then you need to add the filename to the SET(TC_SOURCES...
+section of CMakeLists.txt (this is also parsed by an awk script prior to building)
+
+Debugging
+=========
+
+On desktop, you can debug the tests by running gdb on the test program:
+
+    $ cd automated-tests
+    $ gdb build/src/dali/tct-dali-core
+    gdb> r <TestCase>
+
+replace `<TestCase>` with the name of the failing testcase.
+
+For example, using testcase UtcDaliLoadCompletion from the dali-platform-abstraction test suite:
+
+    $ gdb build/src/dali-platform-abstraction/tct-dali-platform-abstraction-core
+    gdb> r UtcDaliLoadCompletion
+
+
+On target, you can re-install the test RPM and associated debug RPMs manually using
+
+    sdb push <test-package>.rpm /tmp
+
+After installing the rpm and it's debug RPMs, you can find the executable in /opt/usr/bin/tct-dali-core. First ensure you have smack permissions set:
+
+    chsmack -e "^" /usr/bin/gdb
+    chsmack -e "^" /opt/usr/bin/tct-dali-adaptor-core/tct-dali-adaptor-core
+
+then run it under gdb as above.
+
+
+Troubleshooting
+===============
+
+If when running tct-mgr tests, if "Health-Check get" fails and leaves a white screen on the device, you will need to run `tct-config-device.sh` from your `web-tct/tools` directory (wherever you untarred it) and power cycle your handset. If that still fails, you can work-around the issue by running "`mkdir –p /opt/usr/media/Documents/tct/`" on target – you may also need to kill the getCapabilities app from App Manager on the handset)
+
+If the test results show that the test cases fail with "Undefined reference to XXX", it means you have probably failed to update the dali packages on target.
+
+If all the tests are failing then make sure that you have enabled the engineering mode on the target with the 'change-booting-mode.sh --update' command in sdb shell, as the tests may not have installed correctly.
diff --git a/automated-tests/build.sh b/automated-tests/build.sh
new file mode 100755 (executable)
index 0000000..becb278
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+
+TEMP=`getopt -o rn --long rebuild,no-gen,enable-profile: \
+     -n 'genmake' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+opt_rebuild=false
+opt_generate=true
+enable_profile=""
+
+while true ; do
+    case "$1" in
+        -r|--rebuild) opt_rebuild=true ; shift ;;
+        -n|--no-gen)  opt_generate=false ; shift ;;
+        --enable-profile) enable_profile=$2 ; shift ;;
+        --) shift ; break ;;
+        *) shift ;;   # Ignore
+    esac
+done
+
+if [ false == $opt_rebuild -o ! -d "build" ] ; then
+    rm -rf build
+    mkdir build
+fi
+
+function build
+{
+    if [ $opt_generate == true -o $opt_rebuild == false ] ; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+    fi
+    (cd build ; cmake .. -DMODULE=$1 -DENABLE_PROFILE=$enable_profile; make -j7 )
+}
+
+if [ -n "$1" ] ; then
+  echo BUILDING ONLY $1
+  build $1
+else
+  for mod in `ls -1 src/ | grep -v CMakeList `
+  do
+    if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+        echo BUILDING $mod
+        build $mod
+        if [ $? -ne 0 ]; then echo "Build failed" ; exit 1; fi
+    fi
+  done
+fi
diff --git a/automated-tests/coverage.sh b/automated-tests/coverage.sh
new file mode 100755 (executable)
index 0000000..c5fbed7
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+( cd ../build/tizen ; make cov_data )
+
+# From lcov version 1.10 onwards, branch coverage is off by default and earlier versions do not support the rc option
+LCOV_OPTS=`if [ \`printf "\\\`lcov --version | cut -d' ' -f4\\\`\n1.10\n" | sort -V | head -n 1\` = 1.10 ] ; then echo "--rc lcov_branch_coverage=1" ; fi`
+
+for i in `find . -name "*.dir"` ; do
+    (
+        cd $i
+        echo `pwd`
+        covs=( `ls *.gcda 2>/dev/null` )
+        if [[ $? -eq 0 ]]
+        then
+            lcov $LCOV_OPTS --directory . -c -o dali.info
+            lcov $LCOV_OPTS --remove dali.info "/usr/include/*" "*/automated-tests/*" "*/dali-env/*" -o dali.info
+            if [ ! -s dali.info ]
+            then
+              rm -f dali.info
+            fi
+        fi
+    )
+done
+
+(
+    cd .. ;
+    genhtml $LCOV_OPTS -o build/tizen/doc/coverage `find . -name dali.info`
+)
+
+echo "Coverage output: ../build/tizen/doc/coverage/index.html"
diff --git a/automated-tests/execute.sh b/automated-tests/execute.sh
new file mode 100755 (executable)
index 0000000..04dbd1f
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+TEMP=`getopt -o hsr --long help,serial,rerun -n 'execute.sh' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+function usage
+{
+    echo -e "Usage: execute.sh\t\tExecute test cases from all modules in parallel"
+    echo -e "       execute.sh <testmodule>\tExecute test cases from the given module in parallel"
+    echo -e "       execute.sh -s\t\tExecute test cases in serial using Testkit-Lite"
+    echo -e "       execute.sh -r\t\tExecute test cases in parallel, re-running failed test cases in serial afterwards"
+    echo -e "       execute.sh <testcase>\tFind and execute the given test case"
+    exit 2
+}
+
+opt_serial=0
+opt_rerun=""
+while true ; do
+    case "$1" in
+        -h|--help)     usage ;;
+        -s|--serial)   opt_serial=1 ; shift ;;
+        -r|--rerun)    opt_rerun="-r" ; shift ;;
+        --) shift; break;;
+        *) echo "Internal error $1!" ; exit 1 ;;
+    esac
+done
+
+function execute
+{
+    scripts/tctestsgen.sh $1 `pwd` desktop $2
+    testkit-lite -f `pwd`/tests.xml -o tct-${1}-core-tests.xml  -A --comm localhost
+    scripts/add_style.pl $1
+}
+
+
+
+# Clean up old test results
+rm -f tct*core-tests.xml
+
+# Clean up old coverage data
+if [ -d ../build/tizen ] ; then
+    rm -f ../build/tizen/dali-core/.libs/*.gcda
+fi
+
+find build \( -name "*.gcda" \) -exec rm '{}' \;
+
+ASCII_BOLD="\e[1m"
+ASCII_RESET="\e[0m"
+
+if [ $opt_serial = 1 ] ; then
+    # Run all test case executables serially, create XML output
+    if [ -n "$1" ] ; then
+        execute $1 $*
+    else
+        for mod in `ls -1 src/ | grep -v CMakeList `
+        do
+            if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+                echo -ne "$ASCII_BOLD"
+                echo -e "Executing $mod$ASCII_RESET"
+                execute $mod $*
+            fi
+        done
+    fi
+
+    scripts/summarize.pl
+else
+    # if $1 is an executable filename, execute it·
+
+    if [ -z "$1" ] ; then
+        # No arguments:
+        # Execute each test executable in turn, using parallel execution
+        for mod in `ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
+        do
+            echo -e "$ASCII_BOLD"
+            echo -e "Executing $mod$ASCII_RESET"
+            build/src/$mod/tct-$mod-core $opt_rerun
+        done
+
+    elif [ -f "build/src/$1/tct-$1-core" ] ; then
+        # First argument is an executable filename - execute only that with any
+        # remaining arguments
+        module=$1
+        shift;
+        build/src/$module/tct-$module-core $opt_rerun $*
+
+    else
+       # First argument is not an executable. Is it a test case name?
+       # Try executing each executable with the test case name until success/known failure
+        for mod in `ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
+        do
+            output=`build/src/$mod/tct-$mod-core $1`
+            ret=$?
+            if [ $ret -ne 6 ] ; then
+               echo $output
+               if [ $ret -eq 0 ] ; then echo -e "\nPassed" ; fi
+               exit $ret
+            fi
+        done
+        echo $1 not found
+    fi
+fi
diff --git a/automated-tests/images/README.md b/automated-tests/images/README.md
new file mode 100644 (file)
index 0000000..3a9d7a3
--- /dev/null
@@ -0,0 +1,17 @@
+% Images for Dali Adaptor Automated Testing
+
+Images used in automated tests for the dali-adaptor project.
+These images include broken files to test error handling as well as valid
+images.
+
+Truncated files are an interesting case and are a plausible consequence of IO
+errors such as network disconnection during downloading of an image by an
+application.
+Some image codecs can sometimes deliver a partial image for such a truncated
+file.
+It is thus a policy decision for us whether to return an image like this to the
+application, to show some junk to the user, or suppress it as a failed load,
+and these tests should demonstrate that that policy is applied for all relevant
+formats.
+
+
diff --git a/automated-tests/images/error-bits.gif b/automated-tests/images/error-bits.gif
new file mode 100644 (file)
index 0000000..02d3df2
Binary files /dev/null and b/automated-tests/images/error-bits.gif differ
diff --git a/automated-tests/images/error-bits.gif.buffer b/automated-tests/images/error-bits.gif.buffer
new file mode 100644 (file)
index 0000000..3c25f9d
--- /dev/null
@@ -0,0 +1,131 @@
+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0\0\0\0\0\0\0\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0\0\0\0\0\0\0\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?
\ No newline at end of file
diff --git a/automated-tests/images/frac.24.bmp b/automated-tests/images/frac.24.bmp
new file mode 100644 (file)
index 0000000..92d81b4
Binary files /dev/null and b/automated-tests/images/frac.24.bmp differ
diff --git a/automated-tests/images/frac.jpg b/automated-tests/images/frac.jpg
new file mode 100644 (file)
index 0000000..336427d
Binary files /dev/null and b/automated-tests/images/frac.jpg differ
diff --git a/automated-tests/images/frac.png b/automated-tests/images/frac.png
new file mode 100644 (file)
index 0000000..307e83b
Binary files /dev/null and b/automated-tests/images/frac.png differ
diff --git a/automated-tests/images/interlaced.gif b/automated-tests/images/interlaced.gif
new file mode 100644 (file)
index 0000000..42b5323
Binary files /dev/null and b/automated-tests/images/interlaced.gif differ
diff --git a/automated-tests/images/interlaced.gif.buffer b/automated-tests/images/interlaced.gif.buffer
new file mode 100644 (file)
index 0000000..dd26e81
Binary files /dev/null and b/automated-tests/images/interlaced.gif.buffer differ
diff --git a/automated-tests/images/pattern.gif b/automated-tests/images/pattern.gif
new file mode 100644 (file)
index 0000000..4e0032a
Binary files /dev/null and b/automated-tests/images/pattern.gif differ
diff --git a/automated-tests/images/pattern.gif.buffer b/automated-tests/images/pattern.gif.buffer
new file mode 100644 (file)
index 0000000..a94cba8
Binary files /dev/null and b/automated-tests/images/pattern.gif.buffer differ
diff --git a/automated-tests/images/transparency.gif b/automated-tests/images/transparency.gif
new file mode 100644 (file)
index 0000000..007c50e
Binary files /dev/null and b/automated-tests/images/transparency.gif differ
diff --git a/automated-tests/images/transparency.gif.buffer b/automated-tests/images/transparency.gif.buffer
new file mode 100644 (file)
index 0000000..77ef454
--- /dev/null
@@ -0,0 +1 @@
+U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0U\1fÿ\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\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\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*\1f\0*\1f\0*\1f\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\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U\1f\0\7f?\0ª_\0Ô_UÔ\7f\0Ô\7f\7f\7f\0Ô\7f\9f\7f\7f\0\7f_UU\1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\7f\1f\0ª?\0Ô_UÔ_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\9f\0Ô\7fUÿ\9f\0Ô\9fUÿ\9f\9f\9fUª_U*?\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0U\1f\0\7f?\0Ô?\0ª_UÔ_\0Ô_\0Ô_\0Ô_UÔ\7f\0Ô\7f\0Ô_UÔ\7f\0Ô\7fUÿ\7f\7f\9f\7fUÿ\9f\9fUÿ\9f\9fUÿ¿UÔ\9f\7fUU\1f\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0U\1f\0ª?\0ª?\0Ô?UÔ_\0Ô?\0ª_\0Ô_Uª_\0Ô_\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\9f\0ÿ\7f\9f\0ÿ\9f\9fUÿ\9f\0Ô\9fUÿ\9fUÔ¿Uÿ\9f\9fU\7f_\0*\1f\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª?\0ª?UÔ?\0ª_\0Ô?\0ª_UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\9f\9fUÿ\9f\9f\9fUÿ\9fUÔ¿Uÿ\9fUÿ\9fUÔ¿Uÿ\9fUÿ¿Uª\7fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0U\1f\0ª\1f\0ª\1fUª?\0Ô?\0Ô?\0Ô_Uª?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\0Ô\9f\7f\0ÿ\9f\9f\0ÿ\9f\9fUÿ¿UÔ\9fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ\9fUU?U\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª\1f\0ª?\0ª\1f\0Ô?\0ª?Uª?\0Ô_\0Ô?\0Ô_\0ª_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\9f\0Ô\7fUÿ\9f\9fUÿ\9f\9fUÿ\9f\9fUÿ\9fUÔ¿Uÿ\9fUÔ¿Uÿ\9f\9fUÿ\9fUÔ¿U\7f_\0*\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª\1fUª?\0ª\1f\1f\0ª?\0Ô?\0Ô?\0ª?UÔ_\0ª?UÔ_\0Ô_\0ª_UÔ_\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0ÿ\7f\7f\0Ô\7f\9f\0ÿ\7f\9fUÿ\9f\9fUÿ¿Uÿ\9fUÔ¿Uÿ\9f\9fUÿ¿UÔ\9fUÿ\9f\9fU\7f_U*\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿ\0\0\0\0\0\0U\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1fUÔ?\0ª?UÔ?\0ª_\0Ô?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7f\7f\0Ô\7f\7f\9f\0ÿ\7f\9f\9f\0ÿ\9f\9f\0ÿ\9f\9fUÿ\9f\9fUÿ¿Uÿ\9fUÔ¿Uÿ\9fUÿ\9f\9f\9fU\7f?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\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\0\0\0\0U\1f\0ª\1f\0ª\1f\1f\0ª?UÔ\1f\0ª\1f\0ª\1f\0ª?\0ª?\0Ô?UÔ?\0ª_UÔ?\0ª_\0Ô_UÔ_\0ª_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7fUÿ\7f\0Ô\7f\7f\0ÿ\9f\7f\9fUÿ\9f\9fUÿ\9f\0Ô\9fUÿ\9f\9f\0ÿ\9f\9fUÿ\9fUÔ¿\0ÿ\9f\9f\9fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª\9fªÿûðU_U\0\0\0\0\0\0\0\0\0U\1f\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª?UÔ\1f\0ª?\0ª?\0Ô_\0Ô?\0ª_\0Ô?\0Ô_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\7f\9f\7f\0ÿ\9f\9f\0Ô\9fUÿ\9f\9fUÿ\9f\9fUÿ¿UÔ\9fUÿ\9f\9fUÿ\9f\9fUÿ\9f\0Ô\7f\7fUU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿûðÿßÿÀÜÀU?U\0\0\0\0\0\0U\1f\0ª\1f\0ª\1f\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\0ª\1f\0ª?UÔ\1f\0ª?UÔ?\0ª_UÔ?\0Ô_Uª_\0Ô_\0Ô_UÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\0ÿ\7f\7f\7f\0ÿ\9f\7f\9f\0ÿ\9f\9f\9f\0ÿ\9f\9fUÿ\9f\0Ô\9f\9fUÿ\9f\9fUÿ\9f\0Ô\7fU\7f_\0*\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÿûðÿûðÿßÿÿûðÿÿÿÿûðÀÜÀU?U\0\0\0\0\0\0U\1f\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1fUª?\0ª\1f\0ª\1f\0ª?\0Ô?\0ª?\0Ô_\0Ô?\0ª?\0Ô_UÔ_\0ª_\0Ô_UÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\9f\0Ô\7f\9fUÿ\7f\0Ô\9f\9fUÿ\9f\9fUÿ\9f\9f\9fUÿ\9f\9f\0Ô\7f\7f\0Ô\9fUÿ\7f\7fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80ÀÜÀÿßÿÿÿÿÿûðÿßÿÿûðÿûðÿßÿÿûðÔ¿ªU?U\0\0\0*\1f\0U\1f\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1fUª?\0ª?UÔ?\0ª?UÔ_\0Ô?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7f\7f\0ÿ\7f\7fUÿ\7f\0Ô\7f\9fUÿ\7f\0Ô\7f\7f\0ÿ\9f\7f\0Ô\9fUÿ\7f\0Ô\9fUÿ\7f\9f\0ÿ\7f\7f\7f\0Ô\7fUª_\0*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_U  ¤ÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðª\9fª*?U\0\0\0\0\0\0\80\80\80ª\7f\1f\0ª?\0ª\1fUª?\0ª\1f\0Ô\1f\0ª\1fUª?\0ª\1f\0Ô?\0ª\1f\0ª\1f\0ª\1f\0Ô?\0ª?\0Ô?\0ª_UÔ?\0ª_\0Ô_\0ª_UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7fUÿ\9f\0Ô\7f\9f\7fUÿ\9f\0Ô\7f\9f\0Ô\7f\9f\7f\0Ô\9f\7f\0Ô\7f\7f\0\7f?U\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\7f_UÀÜÀÿßÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿ  ¤*\1fU\0\0\0*\1f\0  ¤ÌÌÿÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª?Uª\1f\0Ô?Uª?\0Ô_\0Ô?\0ª?UÔ_\0Ô_\0Ô_Uª_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\0Ô\7f\9f\0Ô\7f\7f\0ÿ\7f\9f\0Ô\7f\7fUÿ\7f\7f\0ÿ\7f\7fUÿ\7f\0Ô\7f\7f\0Ô\7fUª_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûð  ¤*?\0\0\0\0*\1fU  ¤ÀÜÀÔßÿÔ\7f\1f\0ª?\0ª\1f\1f\0Ô?\0ª\1f\0ª\1fUÔ?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0Ô?\0ª?UÔ_\0Ô?\0ª?\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\7f\0Ô\7f\7fUÿ\7f\0Ô\7f\9f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÔ_\0U?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª\9fªÔßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÔßÿÿûð\80\80\80\0\0\0\0\0\0*?U  ¤ÀÜÀÔ¿ÿÿûðÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?Uª\1f\0Ô\1fUª?\0ª\1f\1f\0ª?UÔ?\0ª?\0Ô_\0ª?UÔ_\0ª?\0Ô_\0ª_UÔ_\0ª_\0Ô_UÔ_\0Ô\7f\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\9f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÔ_\0Ô\7fUÔ_\0ª_U*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿûðÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûð\80\80\80*\1f\0\0\0\0U?U  ¤ÀÜÀÿßÿÔߪÿßÿª\9fªª\1f\0ª?\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0ª?\0Ô?Uª?\0Ô_\0Ô?\0Ô_UÔ?\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0ÿ\7f\7f\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÿûðÿûðÿÿÿÿßÿÿûðÿÿÿÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÀÜÀ\80\80\80\0\0\0\0\0\0U?Uª¿ªÔßÿÔߪÿßÿÿûðÿûðÔ\7f\1f\0ª\1f\0ª?\0ª\1f\0ª?Uª\1f\0ª\1f\0Ô?\0ª\1f\1f\0ª?Uª\1f\0ª\1f\1f\0ª\1f\1f\0Ô?\0ª?\0Ô?Uª_\0Ô?\0ª?\0Ô_Uª?\0Ô_\0Ô_\0ª_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô_\0Ô\7fUÔ_\0Ô_UÔ_\0Ô_\0\7f?\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80ÀÜÀÿßÿÿÿÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÀÜÀ\80\80\80\0\0\0\0\0\0U_Uª¿ªÔßÿÿߪÔßÿÿûðÔßÿÿûðÔ\9fªª\1f\0ª?UÔ\1f\0ª\1f\1f\0ª?\0ª\1f\1f\0ª?\0ª\1f\0Ô\1f\0ª\1f\0ª?\0Ô\1f\0ª?\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0ª_UÔ?\0Ô_\0Ô?\0ª_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô_UÔ_\0Ô_\0Ô_\0Ô_UÔ_\0ª?U*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_U  ¤ÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðU_U\0\0\0\0\0\0\7f_U¦ÊðÿÌÿÀÜÀÿßÿÿûðÿûðÿûðÿÿÿÔ\9fªª?Uª\1f\0ª\1f\0ª?\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\1f\0ª\1f\0ª?\0Ô?Uª?\0Ô?\0ª_\0Ô?Uª_\0Ô?\0Ô_Uª_\0Ô_\0ª_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ_\0Ô\7fUÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0ª_\0Ô_\0ª_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80Ô¿ªÔßÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÔÿÿÿûðÿûðÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÔ¿ªU?U\0\0\0\0\0\0U_UÀÜÀÔßÿÿߪÔÿÿÿûðÔßÿÿÿÿÿÿÿÿÿÿÔ\9fªÔ?\0ª?\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0Ô\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0Ô\1f\0ª?Uª\1f\0ª?\0Ô?\0ª?UÔ_\0Ô?\0Ô_\0ª?\0Ô?\0Ô_UÔ_\0Ô_\0Ô_Uª_\0Ô_UÔ_\0Ô\7f\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0ª_\0Ô_UÔ_\0Ô_UÔ?\0\7f?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÀÜÀU?U\0\0\0*\1f\0\7f_UÔ¿ªÿßÿÔßÿÿûðÿßÿÿûðÿÿÿÿÿÿÿÿÿÿûðÔ¿ªÔ_Uª\1f\0ª?\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª?\0Ô?\0ª?\0Ô?Uª_\0Ô?Uª_\0Ô?\0ª?\0Ô_UÔ_\0Ô_\0Ô_\0ª_UÔ_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô_UÔ_\0Ô_\0ª_UÔ_\0ª_\0Ô_UÔ_\0Ô_\0ª?\0Ô?\0ª_U\7f?\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª¿ªÔßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÔÿÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔ¿ªU?U\0\0\0\0\0\0\7f_UÔ¿UÿßÿÀÜÀÿûðÿûðÿûðÿÿÿÿûðÿÿÿÿûðÿÿÿÀÜÀÔ_Uª?Uª\1f\0ª\1fUª?\0ª\1f\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0Ô?\0ª\1f\0ª?Uª\1f\0Ô\1f\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0Ô_\0Ô?\0ª_UÔ?\0ª?\0Ô?\0ª_UÔ?\0Ô_\0Ô_Uª_\0Ô_Uª_\0Ô_\0ª_UÔ_\0ª_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0ª?\0Ô_Uª?\0Ô_\0Ô?\0ª?\0U\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿÿÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿ  ¤*\1fU\0\0\0*\1f\0\7f_Uÿ\9fUÿ¿UÀÜÀÿûðÿßÿÿûðÿÿÿÿÿÿÿÿÿÿÿÿÔÿÿÿßÿÿßÿÔ\7f\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0Ô?Uª\1f\0ª\1fUÔ?\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0ª?\0ª\1fUª?\0ª\1f\0ª?\0Ô?Uª?\0ª?UÔ_\0Ô?\0Ô_\0Ô_Uª?\0Ô_\0ª?\0Ô_Uª?\0Ô_\0Ô?\0Ô_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_Uª?\0Ô_\0ª?\0Ô?UÔ_\0ª?\0Ô_UÔ?\0ª_Uª?\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª¿ªÿßÿÿûðÿÿÿÿÿÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûð  ¤*?\0\0\0\0*\1f\0ª\7fUÿ\9fUÔ¿Uÿ¿ªÿߪÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÿÿÿûðÿûðÿûðÔßÿÔ\9fªª\1f\0ª?UÔ\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\0Ô\1f\1f\0ª\1f\0ª\1f\0ª\1f\1f\0ª?\0Ô?\0ª?\0ª?\0Ô?Uª?\0Ô_\0Ô?\0Ô?UÔ_\0ª?\0Ô_\0Ô?Uª_\0Ô?\0ª?\0Ô?Uª?\0Ô?\0ª?\0Ô_\0Ô?UÔ_\0ª?\0Ô_\0Ô?\0ª?\0Ô_\0ª?\0Ô?UU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûð\80\80\80*\1fU\0\0\0*\1f\0ª\7f\9fUÿ¿UÔ\9fUÿ¿UÿßÿÿûðÿÿÿÿÿÿÿûðÿûðÿßÿÿûðÔßÿÿûðÀÜÀÔ\9fªÔ?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\1f\0ª?Uª\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0ª?\0ª\1fUÔ?\0ª?\0ª\1f\0ª\1f\1f\0Ô?Uª?\0Ô?\0ª?\0Ô?Uª_\0ª?\0Ô_\0Ô?Uª?\0Ô_\0ª?\0Ô_UÔ?\0ª_\0Ô_\0Ô?Uª_\0Ô?\0ª_\0Ô?\0Ô_Uª?\0Ô_Uª?\0Ô?Uª?\0ª?\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÔßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿ\80\80\80*\1f\0\0\0\0U?\0ª\7fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ¿UÿߪÿÿÿÿÿÿÿÿÿÔßÿÿûðÔÿÿÿûðÔßÿÿûðÿßÿÔ¿ªª_Uª?\0ª\1f\0ª\1fUÔ?\0ª\1f\0ª\1f\0Ô?\0ª\1f\0ª?\0Ô\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1f\0ª?\0ª\1f\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0ª?UÔ?\0ª_\0Ô?\0Ô?UÔ_\0ª?\0Ô_\0Ô?Uª?\0Ô_\0Ô?Uª_\0Ô?Uª?\0Ô?\0ª?\0ª?\0Ô?\0ª?\0ª\1f\0Ô\1fUU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80Ô¿ªÔßÿÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿ\80\80\80*\1f\0\0\0\0U?Uª\7fUÿ¿UÔ\9fUÿ\9fUÔ¿Uÿ\9f\9fªÿߪÿÿÿÿÿÿÿûðÿûðÿûðÔßÿÿûðÀÜÀÿßÿÀÜÀÔߪÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\1f\0ª\1fUª?\0ª\1f\1f\0Ô?Uª\1f\0ª\1f\0Ô?\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1f\0ª?\0ª?Uª?\0Ô?\0ª?\0Ô?Uª?\0ª?\0Ô?\0ª?UÔ?\0ª_\0Ô?\0ª?\0Ô?\0ª?\0Ô?\0ª?\0ª?UÔ?\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÀÜÀ\80\80\80*\0\0\0\0\0U?\0ª\7fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ\9fUÿ\9fUÿ\9fUÔߪÿÿÿÿßÿÔÿÿÿßÿÔßÿÿߪÔßÿÿûðÀÜÀÿÌÿÀÜÀÔ\7fªª?\0Ô\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª\1f\0Ô?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\1f\0Ô\1f\0ª\1f\0ª?Uª\1f\0ª?\0Ô?\0ª?UÔ?\0ª?\0ª?\0Ô?Uª?\0ª?UÔ?\0ª?Uª?\0Ô?\0ª?\0ª\1f\0ª\1f\0ª?\0Ô\1f\0ª\1f\0\7f\1f\0U\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\7f_Uª¿ªÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÔÿÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿû
\ No newline at end of file
diff --git a/automated-tests/packaging/core-dali-adaptor-tests.spec b/automated-tests/packaging/core-dali-adaptor-tests.spec
new file mode 100644 (file)
index 0000000..a6c1dd1
--- /dev/null
@@ -0,0 +1,54 @@
+%define MODULE_NAME dali-adaptor
+%define MODULE_LIBNAME dali-adaptor
+Name:       core-%{MODULE_NAME}-tests
+Summary:    Core API unit TC (%{name})
+Version:    0.1
+Release:    0
+Group:      Development/Tools
+License:    Apache License, Version 2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires: dali-adaptor
+Requires: dali
+BuildRequires:  dali-integration-devel
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali)
+BuildRequires:  boost-devel
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(ecore)
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/opt/usr/share/license
+cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/opt/usr/share/license/%{name}
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/opt/usr/share/license/%{name}
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
diff --git a/automated-tests/packaging/core-dali-platform-abstraction-tests.spec b/automated-tests/packaging/core-dali-platform-abstraction-tests.spec
new file mode 100644 (file)
index 0000000..89161ab
--- /dev/null
@@ -0,0 +1,54 @@
+%define MODULE_NAME dali-platform-abstraction
+%define MODULE_LIBNAME dali-platform-abstraction
+Name:       core-%{MODULE_NAME}-tests
+Summary:    Core API unit TC (%{name})
+Version:    0.1
+Release:    0
+Group:      Development/Tools
+License:    Apache License, Version 2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires: dali-adaptor
+Requires: dali
+BuildRequires:  dali-integration-devel
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali)
+BuildRequires:  boost-devel
+BuildRequires:  cmake
+
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/opt/usr/share/license
+cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/opt/usr/share/license/%{name}
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/opt/usr/share/license/%{name}
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
diff --git a/automated-tests/scripts/add_all_smack_rule.sh b/automated-tests/scripts/add_all_smack_rule.sh
new file mode 100755 (executable)
index 0000000..8efb158
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+echo ""
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               echo "Comment"
+               continue
+       fi
+
+       echo "echo \"$rule\" > /smack/load2"
+       echo "$rule" > /smack/load2
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_smack_rule.sh b/automated-tests/scripts/add_smack_rule.sh
new file mode 100755 (executable)
index 0000000..22fe5ee
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+
+echo "sdb root on"
+sdb root on
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               #echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               #echo "Comment"
+               continue
+       fi
+
+       echo "sdb shell \"echo $rule > /smack/load2\""
+       sdb shell "echo $rule > /smack/load2"
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_style.pl b/automated-tests/scripts/add_style.pl
new file mode 100755 (executable)
index 0000000..e958842
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use strict;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $MOD_NAME = $ARGV[0];
+my $results_xml = "tct-$MOD_NAME-core-tests.xml";
+my $results_out = "results_xml.$$";
+
+# Copy $results_xml, writing new stylesheet line:
+# Write <?xml-stylesheet type="text/xsl" href="./style/testresult.xsl"?> as second line
+open RESULTS, "<$results_xml" || die "Can't open $results_xml for reading:$!\n";
+open RESULTS_OUT, ">$results_out" || die "Can't open $results_out for writing:$!\n";
+my $fline = readline RESULTS;
+print RESULTS_OUT $fline;
+print RESULTS_OUT "<?xml-stylesheet type=\"text/xsl\" href=\"./style/testresult.xsl\"?>\n";
+while(<RESULTS>)
+{
+    if( ! /xml-stylesheet/ )
+    {
+        print RESULTS_OUT $_;
+    }
+}
+close RESULTS_OUT;
+close RESULTS;
+unlink $results_xml;
+print `mv $results_out $results_xml`;
diff --git a/automated-tests/scripts/all_smack.rule b/automated-tests/scripts/all_smack.rule
new file mode 100644 (file)
index 0000000..93f2b67
--- /dev/null
@@ -0,0 +1,28 @@
+# calendar-service
+_ calendar-service::svc rwx
+
+# capi-appfw-application
+_ alarm-server::alarm rw
+_ aul::launch x
+_ aul::terminate x
+
+# capi-network-bluetooth
+_ bt-service::admin w
+_ bt-service::manager w
+_ bt-service::gap w
+_ bt-service::spp w
+_ bt:service::opp w
+
+# capi-network-nfc
+_ nfc-manager rwx
+_ nfc-manager::tag rwx
+_ nfc-manager::p2p rwx
+_ nfc-manager::admin rwx
+_ nfc-manager::common rwx
+
+# capi-location-*
+_ location::maps rw
+_ location::client rw
+
+# libmdm
+_ mdm-server::eas rw
diff --git a/automated-tests/scripts/autocompletion.sh b/automated-tests/scripts/autocompletion.sh
new file mode 100755 (executable)
index 0000000..d952c73
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+if [ -z "$TC_PROJECT_DIR" ]; then
+    echo "CoreAPI project directory can't be found. `basename $0` exitting..."
+    exit 1
+fi
+
+_tcbuild () {
+    local cur
+    cur=${COMP_WORDS[$COMP_CWORD]}
+    if [ $COMP_CWORD -eq 1 ]; then
+        COMPREPLY=( $( compgen -W "addmod build install rmmod" -- $cur ) )
+    else #if [ $COMP_CWORD -eq 2 ]; then
+        COMPREPLY=( $( cd $TC_PROJECT_DIR/src; compgen -d -X "common" -- $cur ) )
+    fi
+    return 0
+}
+
+complete -F _tcbuild tcbuild
diff --git a/automated-tests/scripts/init.sh b/automated-tests/scripts/init.sh
new file mode 100755 (executable)
index 0000000..1ccd9ea
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+PROJECT_DIR="$(cd "$(dirname $0)" && cd .. && pwd)"
+
+ln -s $PROJECT_DIR/scripts/tcbuild.sh $PROJECT_DIR/tcbuild
+
+echo "" >> $HOME/.bashrc
+echo "# CoreAPI-tests convenience helpers" >> $HOME/.bashrc
+echo "export TC_PROJECT_DIR=\"$PROJECT_DIR\"" >> $HOME/.bashrc
+echo "source $PROJECT_DIR/scripts/autocompletion.sh" >> $HOME/.bashrc
diff --git a/automated-tests/scripts/retriever.sh b/automated-tests/scripts/retriever.sh
new file mode 100755 (executable)
index 0000000..c1d466d
--- /dev/null
@@ -0,0 +1,212 @@
+#!/bin/bash
+
+USAGE=$(cat <<EOF
+Usage note: retriever.sh [option] [directory]
+Options:
+  none    retrieve TC names with corresponding startup and cleanup functions
+  -f      retrieveve TC name with corresponding "set" and "purpose" clauses
+  -anum   retrieve automatic TC number
+  -mnum   retrieve manual TC number
+
+In case of TC in form of "int tc_name()" script will abort.
+("int tc_name(void)" is a proper function signature)
+EOF
+)
+
+function get_tc_files {
+    CMAKE_FILE="$DIR/CMakeLists.txt"
+    if [ ! -e $CMAKE_FILE ]; then
+        echo "File $CMAKE_FILE not found. Aborting..."
+        exit 1
+    fi
+
+    TC_FILES=$(cat $CMAKE_FILE | awk -vDIR="$DIR" '
+    BEGIN {
+        flag = 0;
+        files = "";
+    }
+    /^SET\(TC_SOURCES/ {
+        flag = 1;
+        next;
+    }
+    /\)/ {
+        if (flag == 1)
+            exit;
+    }
+    !/^ *#/ {
+        if (flag == 1) {
+            if (files == "")
+                files = DIR "/" $1;
+            else
+                files = files " " DIR "/" $1;
+        }
+    }
+    END {
+        print files;
+    }')
+}
+
+function tc_names {
+    if [[ -z "$1" ]]; then
+        exit
+    fi
+
+    awk '
+    BEGIN {
+        OFS = ",";
+        start_fun = "NULL";
+        clean_fun = "NULL";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^void .*startup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        start_fun = $0
+    }
+    /^void .*cleanup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        clean_fun = $0
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)/ {
+        gsub(/^int /, "");
+        gsub(/\(void\).*/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS start_fun OFS clean_fun
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+function tc_anum {
+    awk '
+    BEGIN {
+        count = 0;
+        err_flag = 0;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        count++;
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print count
+        }
+    }
+    ' $*
+}
+
+function tc_mnum {
+    # TODO: fix this hardcoded value
+    echo 0
+}
+
+function tc_fullinfo {
+    awk '
+    BEGIN {
+        OFS=",";
+        purpose = "";
+        set = "default";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^\/\/& set:/ {
+        set = $3;
+        next;
+    }
+    /^\/\/& purpose:/ {
+        purpose = $3;
+        for (i = 4; i <= NF; i++) {
+            purpose = purpose " " $i;
+        }
+        next;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        gsub(/^int /, "");
+        gsub(/\(void\)$/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS set OFS purpose;
+        purpose = "";
+        next
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+
+# usage note and exit:
+# - argument begin with '-' but is not recognised or number of arguments is > 3,
+# - argument doesn't begin with '-' and number of arguments is > 2
+if [[ ( "$1" == -* && ( ! "$1" =~ ^-(anum|mnum|f)$ || $# > 3 ) ) || ( "$1" != -* && $# > 2 ) ]]; then
+    echo -e "$USAGE"
+    exit 1
+fi
+
+# get directory from last argument (or assume current one)
+if [[ ! "$1" =~ ^-(anum|mnum|f)$ ]]; then
+    DIR=${1:-.}
+else
+    DIR=${2:-.}
+fi
+
+# get filename from last argument
+if [[ $# == 3 && -f $DIR/$3 ]] ; then
+    FILE=$3
+elif [[ $# == 2 && -f $DIR/$2 ]] ; then
+    FILE=$2
+fi
+
+#echo "Dir: $DIR  File: $FILE" >& 2
+
+
+# populate $TC_FILES with files declared in CMakeLists.txt
+if [[ -z $FILE ]]; then
+    get_tc_files $DIR
+    if [ $? != 0 ]; then
+        exit 1
+    fi
+    echo "Got all files" >& 2
+else
+    TC_FILES="$DIR/$FILE"
+    echo "TC_FILES: $TC_FILES" >& 2
+fi
+
+
+
+# run appropriate subcommand
+case "$1" in
+    -anum)
+        tc_anum $TC_FILES ;;
+    -mnum)
+        tc_mnum $TC_FILES ;;
+    -f)
+        tc_fullinfo $TC_FILES ;;
+    *)
+        tc_names $TC_FILES ;;
+esac
diff --git a/automated-tests/scripts/summarize.pl b/automated-tests/scripts/summarize.pl
new file mode 100755 (executable)
index 0000000..c90eb89
--- /dev/null
@@ -0,0 +1,109 @@
+#!/usr/bin/perl
+
+use strict;
+use XML::Parser;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $num_tests=0;
+my $num_passes=0;
+my $num_actual_passes=0;
+my $text = "";
+
+sub handle_start
+{
+    my ($p, $elt, %attrs) = @_;
+
+    if($elt =~ /testcase/)
+    {
+        $num_tests++;
+        if($attrs{"result"} eq "PASS")
+        {
+            $num_passes++;
+        }
+    }
+    if($elt =~ /actual_result/)
+    {
+        $text = "";
+    }
+}
+
+sub handle_end
+{
+  my ($p, $elt) = @_;
+  if($elt =~ /actual_result/)
+  {
+      if($text eq "PASS")
+      {
+          $num_actual_passes++;
+      }
+      $text = "";
+  }
+}
+
+sub handle_char
+{
+  my ($p, $str) = @_;
+  $text .= $str;
+}
+
+my($parser) = new XML::Parser(Handlers => {Start => \&handle_start,
+                                           End   => \&handle_end,
+                                           Char  => \&handle_char});
+
+
+# Write summary.xml:
+open SUMMARY, ">summary.xml" || die "Can't open summary.xml for writing:$!\n";
+print SUMMARY << "EOS";
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="./style/summary.xsl"?>
+<result_summary plan_name="Core">
+  <other xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" />
+  <summary test_plan_name="Empty test_plan_name">
+    <start_at>2014-03-21_18_52_41</start_at>
+    <end_at>2014-03-21_18_57_54</end_at>
+  </summary>
+EOS
+
+print "\n\nSummary of all tests:\n";
+my $output_files = `ls tct*core-tests.xml`;
+my $file;
+foreach $file (split /\s+/, $output_files )
+{
+    $num_tests=0;
+    $num_passes=0;
+    $num_actual_passes=0;
+    $text = "";
+
+    $parser->parsefile($file);
+
+    my $pass_rate = sprintf("%5.2f", $num_passes * 100.0 / $num_tests);
+    my $num_fails = $num_tests - $num_passes;
+    my $fail_rate = sprintf("%5.2f", $num_fails * 100.0 / $num_tests);
+
+    my $suite_name = $file;
+    $suite_name =~ s/\.xml$//;
+
+    print "$suite_name: $num_passes tests passed out of $num_tests ( $pass_rate% )\n";
+
+print SUMMARY << "EOS2";
+  <suite name="$suite_name">
+    <total_case>$num_tests</total_case>
+    <pass_case>$num_passes</pass_case>
+    <pass_rate>$pass_rate</pass_rate>
+    <fail_case>$num_fails</fail_case>
+    <fail_rate>$fail_rate</fail_rate>
+    <block_case>0</block_case>
+    <block_rate>0.00</block_rate>
+    <na_case>0</na_case>
+    <na_rate>0.00</na_rate>
+  </suite>
+EOS2
+}
+
+print SUMMARY "</result_summary>\n";
+close SUMMARY;
+
+print "Summary of results written to summary.xml\n";
diff --git a/automated-tests/scripts/tcbuild.sh b/automated-tests/scripts/tcbuild.sh
new file mode 100755 (executable)
index 0000000..b604675
--- /dev/null
@@ -0,0 +1,215 @@
+#!/bin/bash
+
+#---------- DEBUG_BEGIN ----------
+#ARG="-d" # debug-on flag, might be set as $1
+# keyprompt "introductory message" -- wait until any key pressed
+function keyprompt { echo -ne "\n\e[1;31m$1 -- " && read -n 1 && echo -e "\n\e[0m"; }
+# d_bp -- breakpoint at which user need to press any key to proceed
+function d_bp { if [[ "$ARG" == "-d" ]]; then keyprompt "d >> Press any key"; fi }
+# d_showVar VARNAME -- print bash variable name
+function d_showVar { if [ "$ARG" == "-d" -a -n "$1" ]; then echo "d >> ${1} = ${!1}"; fi }
+# d_print "message" -- print a debug message
+function d_print { if [ "$ARG" == "-d" -a -n "$1" ]; then echo -e "d >> $1"; fi }
+#----------  DEBUG_END  ----------
+
+PROJECT_DIR="$(cd "$(dirname $0)" && pwd)"
+d_showVar PROJECT_DIR
+
+function gbs_profile {
+perl -e "
+use Config::Tiny;
+my \$Config = Config::Tiny->read( \"\$ENV{HOME}/.gbs.conf\" );
+my \$profile = \$Config->{general}->{profile};
+\$profile =~ s/profile.//;
+print \$profile;"
+}
+
+PROFILE=`gbs_profile`
+RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"
+d_showVar RPM_DIR
+
+function add_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` addmod <module_name> [module_lib_name]"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+    MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+    d_showVar MODULE_NAME_C
+    MODULE_NAME_U=$(echo $MODULE_NAME | sed -e 's/-/_/')
+    d_showVar MODULE_NAME_U
+#    MODULE_LIBNAME=${2:-capi-$MODULE_NAME}
+    MODULE_LIBNAME=$1
+    d_showVar MODULE_LIBNAME
+
+    echo "Adding $MODULE_NAME module to project..."
+    d_bp
+    cd $PROJECT_DIR
+    # prepare .spec file
+    echo "-- Generating packaging/core-$MODULE_NAME-tests.spec file"
+    if [ ! -d packaging ]; then mkdir packaging; fi
+    sed -e "s:\[MODULE_NAME\]:$MODULE_NAME:g" -e "s:\[MODULE_LIBNAME\]:$MODULE_LIBNAME:g" \
+        templates/core-\[module_name\]-tests.spec > packaging/core-$MODULE_NAME-tests.spec
+    # prepare src directory
+    mkdir src/$MODULE_NAME
+    echo "-- Generating src/$MODULE_NAME/CMakeLists.txt file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" -e "s:%{MODULE_LIBNAME}:$MODULE_LIBNAME:g" \
+        templates/src-directory/CMakeLists.txt > src/$MODULE_NAME/CMakeLists.txt
+    echo "-- Generating src/$MODULE_NAME/tct-$MODULE_NAME-core.c file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" \
+        templates/src-directory/tct-\[module_name\]-core.c > src/$MODULE_NAME/tct-$MODULE_NAME-core.c
+    echo "-- Generating src/$MODULE_NAME/utc-$MODULE_NAME.c file"
+    sed -e "s:%{MODULE_NAME_U}:$MODULE_NAME_U:g" -e "s:%{MODULE_NAME_C}:$MODULE_NAME_C:g" \
+        templates/src-directory/utc-\[module_name\].c > src/$MODULE_NAME/utc-$MODULE_NAME.c
+    echo "Task finished successfully"
+}
+
+function rm_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` rmmod <module_name>"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+
+    echo "Removing $MODULE_NAME module from project..."
+    d_bp
+    echo "---- Updating /opt/tct/packages/package_list.xml"
+    scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/packages/package_list.xml 1
+    if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+   # echo "---- Updating test plans"
+   # scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/manager/plan/*.xml 1
+   # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+
+    cd $PROJECT_DIR
+    echo "-- Removing packaging/core-$MODULE_NAME-tests.spec file"
+    rm packaging/core-$MODULE_NAME-tests.spec
+    echo "-- Removing src/$MODULE_NAME directory"
+    rm -r src/$MODULE_NAME
+    echo "Task finished successfully"
+}
+
+function build {
+    if [ -n "$1" ]; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        cp packaging/core-$1-tests.spec ../packaging
+        cp .gitignore-without-autogenerated-files .gitignore
+        gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs | \
+            tee build.log | stdbuf -o0 sed -e 's/error:/\x1b[1;91m&\x1b[0m/' \
+                                           -e 's/warning:/\x1b[93m&\x1b[0m/'
+        rm ../packaging/core-$1-tests.spec
+        cp .gitignore-with-autogenerated-files .gitignore
+    else
+        echo "Build requires a module name"
+        exit 1
+    fi
+}
+
+function inst {
+    if [ -z "$1" ]
+    then
+        for mod in `ls -1 src/ | grep -v CMakeLists`
+        do
+
+       if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+            PKG_NAME="core-$mod-tests"
+            d_showVar PKG_NAME
+            VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+            d_showVar VER
+            PKG_VNAME="$PKG_NAME-$VER"
+            d_showVar PKG_VNAME
+            PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+            d_showVar PKG_FNAME
+
+            if [ -f "$RPM_DIR/$PKG_FNAME" ]
+            then
+                inst $mod
+                echo ""
+            fi
+       fi
+        done
+    else
+        cd $PROJECT_DIR
+        # setting variables
+        MOD_NAME="$1"
+        d_showVar MOD_NAME
+        PKG_NAME="core-$MOD_NAME-tests"
+        d_showVar PKG_NAME
+        VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+        d_showVar VER
+        PKG_VNAME="$PKG_NAME-$VER"
+        d_showVar PKG_VNAME
+        PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+        d_showVar PKG_FNAME
+        TCT_DIR="opt/tct-$MOD_NAME-core-tests"
+        d_showVar TCT_DIR
+
+        echo "Deploying $MOD_NAME suite to tct-mgr..."
+        d_bp
+        # prepare tct directory and files
+        echo "-- Preparing suite .zip file..."
+        echo "---- Creating /tmp/$TCT_DIR directory"
+        rm -r /tmp/opt > /dev/null 2>&1
+        mkdir -p /tmp/$TCT_DIR
+        # README
+        echo "---- Copying /tmp/$TCT_DIR"
+        cp templates/tct-package/README /tmp/$TCT_DIR
+        # rpm
+        echo "---- Copying /tmp/$TCT_DIR package"
+        cp $RPM_DIR/$PKG_FNAME /tmp/$TCT_DIR
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # inst.sh
+        echo "---- Generating /tmp/$TCT_DIR/inst.sh file"
+        sed -e "s:%{PKG_NAME}:\"$PKG_NAME\":g" -e "s:%{PKG_FULLNAME}:\"$PKG_FNAME\":g" \
+            -e "s:%{PKG_DIR}:\"/opt/usr/media/tct/$TCT_DIR\":g" \
+            templates/tct-package/inst.sh > /tmp/$TCT_DIR/inst.sh
+        chmod a+x /tmp/$TCT_DIR/inst.sh
+        # tests.xml
+        echo "---- Generating /tmp/$TCT_DIR"
+        scripts/tctestsgen.sh $MOD_NAME /tmp/$TCT_DIR target
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # zip
+        echo "---- Preparing /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip file"
+        # clear old zips
+        rm -r /tmp/tct/packages > /dev/null 2>&1
+        mkdir -p /tmp/tct/packages
+        # create new zip
+        ( cd /tmp; zip -r /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip opt > /dev/null 2>&1; )
+        # deployment
+        echo "-- Suite deployment..."
+        echo "---- Copying /opt/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip"
+        cp /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip /opt/tct/packages/
+        echo "---- Updating /opt/tct/packages/package_list.xml"
+        scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/packages/package_list.xml 0
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+       # echo "---- Updating test plans"
+       # for file in `grep -r tct-$MOD_NAME-core-tests /opt/tct/manager/plan/ | cut -d: -f1 | uniq`
+       # do
+       #     scripts/tcpackageslistsgen.sh $MOD_NAME $file
+       # done
+       # scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/manager/plan/Full_test.xml
+       # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        echo "Task finished successfully"
+    fi
+}
+
+if [ -z "$1" ]; then
+    # usage note
+    echo "Usage: `basename $0` <addmod|rmmod|build|install> <module_name> [module_lib_name]"
+    exit 1
+elif [ "addmod" == "$1" ]; then
+    # add new module
+    add_module $2 $3
+elif [ "rmmod" == "$1" ]; then
+    # remove module
+    rm_module $2
+elif [ "build" == "$1" ]; then
+    # build the binary
+    build $2
+elif [ "install" == "$1" ]; then
+    # install
+    inst $2
+else
+    echo "Invalid subcommand: $1"
+fi
diff --git a/automated-tests/scripts/tcheadgen.sh b/automated-tests/scripts/tcheadgen.sh
new file mode 100755 (executable)
index 0000000..c7b7700
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tcheadgen.sh <header_filename.h>"
+    exit 1
+fi
+
+FILE="$PWD/$1"
+TFILE="/tmp/retr.csv"
+HEADER_NAME=$(echo $1 | tr '[:lower:]' '[:upper:]' | sed -e 's/-/_/g' -e 's/\./_/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+
+$SCRIPT_DIR/retriever.sh > $TFILE
+if [ $? -ne 0 ]; then cat $TFILE; exit 1; fi
+awk -F',' -v HEADER_NAME="$HEADER_NAME" '
+    BEGIN {
+        OFS = ", ";
+
+        startup_counter = 0;
+        startup_list[0] = "";
+
+        cleanup_counter = 0;
+        cleanup_list[0] = "";
+
+        testcase_counter = 0;
+        testcase_list[0] = "";
+
+        tc_array_counter = 0;
+        tc_array_list[0] = "";
+
+print "#ifndef __" HEADER_NAME "__"
+print "#define __" HEADER_NAME "__"
+print ""
+print "#include \"testcase.h\""
+print ""
+    }
+    {
+        testcase_list[testcase_counter++] = $1;
+
+        if (startup_counter == 0 || startup_list[startup_counter-1] != $2)
+            startup_list[startup_counter++] = $2;
+
+        if (startup_counter == 0 || cleanup_list[cleanup_counter-1] != $3)
+            cleanup_list[cleanup_counter++] = $3;
+
+        tc_array_list[tc_array_counter++] = "\"" $1 "\", " $1 ", " $2 ", " $3;
+    }
+    END {
+        sc_count = (startup_counter > cleanup_counter) ? startup_counter : cleanup_counter;
+        for (i = 0; i < sc_count; i++) {
+            if (i < startup_counter && startup_list[i] != "NULL")
+print "extern void " startup_list[i] "(void);"
+            if (i < cleanup_counter && cleanup_list[i] != "NULL")
+print "extern void " cleanup_list[i] "(void);"
+        }
+
+print ""
+        for (i = 0; i < testcase_counter; i++)
+print "extern int " testcase_list[i] "(void);"
+
+print ""
+print "testcase tc_array[] = {"
+
+        for (i = 0; i < tc_array_counter; i++)
+print "    {" tc_array_list[i] "},"
+
+print "    {NULL, NULL}"
+print "};"
+print ""
+print "#endif // __" HEADER_NAME "__"
+}' $TFILE > $FILE
diff --git a/automated-tests/scripts/tcpackageslistsgen.sh b/automated-tests/scripts/tcpackageslistsgen.sh
new file mode 100755 (executable)
index 0000000..15ea51f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+if [ -z $1 -o -z $2 ]; then
+    echo "Usage note: tcpackageslistsgen.sh <module_name> <output_file.xml>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+FILE=$2
+if [ ! -f $FILE ]; then
+    echo "No such file: $2"
+    exit
+fi
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+AUTO_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -anum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $AUTO_NUM; exit 1; fi
+MAN_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -mnum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $MAN_NUM; exit 1; fi
+
+TFILE="/tmp/tempfile.xml"
+if [ -f $TFILE ]; then
+    rm $TFILE
+fi
+
+function regen {
+    awk -v RS='\r\n' -v ORS='\r\n' -v MODULE_NAME=$MODULE_NAME -v AUTO_NUM=$AUTO_NUM -v MAN_NUM=$MAN_NUM '    
+    BEGIN {
+        found = 0;
+        replaced = 0;
+    }
+    $0 ~ "<suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">" {
+        found = 1;
+        next
+    }
+    /<\/suite>/ {
+        if (found == 1) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+            found = 0;
+            replaced = 1;
+        } else {
+            print $0;
+        }
+        next
+    }
+    /<\/ns3:testplan>/ {
+        if (replaced == 0) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+print $0
+        } else {
+            print $0
+        }
+        next
+    }
+    {
+        if (found == 0) {
+            print $0;
+        }
+    }' $FILE > $TFILE
+    cat $TFILE > $FILE
+}
+
+regen
diff --git a/automated-tests/scripts/tctestsgen.sh b/automated-tests/scripts/tctestsgen.sh
new file mode 100755 (executable)
index 0000000..1881668
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tctestsgen.sh <module_name>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+TC_DIR="/opt/usr/bin/tct-$1-core"
+if [[ $3 == "desktop" ]] ; then
+  TC_DIR="build/src/$1"
+fi
+
+FILE="$2/tests.xml"
+if [ -a $FILE ]; then
+    rm $FILE
+fi
+TFILE="/tmp/tcs.csv"
+if [ -a $TFILE ]; then
+    rm $TFILE
+fi
+
+function gen {
+    awk -F',' -v MODULE_NAME=$MODULE_NAME -v MODULE_NAME_C=$MODULE_NAME_C -v TC_DIR=$TC_DIR '
+    BEGIN {
+        set = ""
+print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+print "    <?xml-stylesheet type=\"text/xsl\" href=\"./testcase.xsl\"?>";
+print "<test_definition>";
+print "  <suite name=\"tct-"MODULE_NAME"-core-tests\" category=\"Core APIs\">";
+    }
+    {
+        if (set != "" && set != $2) {
+print "    </set>"
+        }
+
+        if (set != $2) {
+            set = $2;
+print "    <set name=\"" set "\">";
+        }
+
+        tcname = $1;
+        tcpurpose = $3
+
+print "      <testcase component=\"CoreAPI/" MODULE_NAME_C "/" set "\" execution_type=\"auto\" id=\"" tcname "\" purpose=\"" tcpurpose "\">";
+print "        <description>";
+
+print "          <test_script_entry test_script_expected_result=\"0\">" TC_DIR "/tct-" MODULE_NAME "-core " tcname "</test_script_entry>";
+print "        </description>";
+print "      </testcase>";
+    }
+    END {
+        if (set != "") {
+print "    </set>"
+        }
+print "  </suite>"
+print "</test_definition>"
+    }' $TFILE > $FILE
+}
+
+(cd $SCRIPT_DIR/..; scripts/retriever.sh -f src/$MODULE_NAME $4 > ${TFILE}_pre)
+if [ $? -ne 0 ]; then cat ${TFILE}_pre; exit 1; fi
+cat ${TFILE}_pre | sort -t',' -k2,2 -s > $TFILE
+gen
diff --git a/automated-tests/src/CMakeLists.txt b/automated-tests/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b2ed538
--- /dev/null
@@ -0,0 +1,9 @@
+include(CMakeDependentOption)
+CMAKE_DEPENDENT_OPTION(UBUNTU_PROFILE "Ubuntu Profile" ON "ENABLE_PROFILE STREQUAL UBUNTU" OFF)
+
+IF( DEFINED MODULE )
+    MESSAGE(STATUS "Building: ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}")
+    ADD_SUBDIRECTORY(${MODULE})
+ELSE( DEFINED MODULE )
+    MESSAGE(FATAL_ERROR "No module selected to build. Aborting...")
+ENDIF( DEFINED MODULE )
diff --git a/automated-tests/src/common/assert.h b/automated-tests/src/common/assert.h
new file mode 100644 (file)
index 0000000..a5d6cff
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _ASSERT_H_
+#define _ASSERT_H_
+#include <stdio.h>
+#include <stdlib.h>
+
+#define assert(exp) \
+    if (!(exp)) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Following expression is not true:\n" \
+                "%s\n", #exp); \
+        return 1; \
+    }
+
+#define assert_eq(var, ref) \
+    if (var != ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are not equal:\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, (int)var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_neq(var, ref) \
+    if (var == ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are equal:\n" \
+                "%s == %s == %d\n", \
+            #var, #ref, #var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_gt(var, ref) \
+    if (var <= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_geq(var, ref) \
+    if (var < ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_lt(var, ref) \
+    if (var >= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_leq(var, ref) \
+    if (var > ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#endif //  _ASSERT_H_
diff --git a/automated-tests/src/common/testcase.h b/automated-tests/src/common/testcase.h
new file mode 100644 (file)
index 0000000..011a452
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _TESTCASE_H_
+#define _TESTCASE_H_
+
+/* pointer to startup/cleanup functions */
+typedef void (*void_fun_ptr)(void);
+
+/* pointer to testcase functions */
+typedef int (*tc_fun_ptr)(void);
+
+/* struct describing specific testcase */
+typedef struct testcase_s {
+    const char* name;
+    tc_fun_ptr function;
+    void_fun_ptr startup;
+    void_fun_ptr cleanup;
+} testcase;
+
+#endif // _TESTCASE_H_
diff --git a/automated-tests/src/dali-adaptor-internal/CMakeLists.txt b/automated-tests/src/dali-adaptor-internal/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8b1bd95
--- /dev/null
@@ -0,0 +1,76 @@
+SET(PKG_NAME "dali-adaptor-internal")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-adaptor-internal")
+
+SET(TC_SOURCES
+    utc-ConditionalWait.cpp
+    utc-Dali-CommandLineOptions.cpp
+    utc-Dali-FontClient.cpp
+    utc-Dali-GifLoader.cpp
+    utc-Dali-ImageOperations.cpp
+    utc-Dali-Lifecycle-Controller.cpp
+    utc-Dali-TiltSensor.cpp
+)
+
+LIST(APPEND TC_SOURCES
+    image-loaders.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-harness.cpp
+    ../dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-application.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gesture-manager.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali
+    ecore
+)
+
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror=return-type" )
+
+# Shouldn't have to do this!
+# But CMake's new auto-escape quote policy doesn't work right.
+CMAKE_POLICY(SET CMP0005 OLD)
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+# Adaptor directories are included in order of most-specific to least specific:
+INCLUDE_DIRECTORIES(
+    ../../../
+    ../../../adaptors/mobile
+    ../../../adaptors/x11
+    ../../../adaptors/common
+    ../../../adaptors/base
+    ../../../adaptors/public-api
+    ../../../adaptors/devel-api
+    ../../../adaptors/devel-api/adaptor-framework
+    ../../../adaptors/public-api/adaptor-framework
+    ../../../adaptors/tizen
+    ../../../adaptors/ubuntu
+    ../../../text
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-adaptor/dali-test-suite-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+    -lpthread
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-adaptor-internal/image-loaders.cpp b/automated-tests/src/dali-adaptor-internal/image-loaders.cpp
new file mode 100644 (file)
index 0000000..0c0efca
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "image-loaders.h"
+#include <dali-test-suite-utils.h>
+
+
+class StubImageLoaderClient : public Dali::TizenPlatform::ResourceLoadingClient
+{
+public:
+  StubImageLoaderClient() {}
+  ~StubImageLoaderClient() {}
+
+  virtual void InterruptionPoint() const {}
+};
+
+AutoCloseFile::AutoCloseFile( FILE *fp )
+: filePtr( fp )
+{
+}
+
+AutoCloseFile::~AutoCloseFile()
+{
+  if ( filePtr )
+  {
+    fclose( filePtr );
+  }
+}
+
+
+ImageDetails::ImageDetails( const char * const _name, unsigned int _width, unsigned int _height )
+: name( _name ),
+  width( _width ),
+  height( _height ),
+  reportedWidth( _width ),
+  reportedHeight( _height ),
+  refBufferSize( _width * _height ),
+  refBuffer( new Dali::PixelBuffer[ refBufferSize ] )
+{
+  LoadBuffer();
+}
+
+ImageDetails::ImageDetails( const char * const _name, unsigned int _width, unsigned int _height, unsigned int _reportedWidth, unsigned int _reportedHeight )
+: name( _name ),
+  width( _width ),
+  height( _height ),
+  reportedWidth( _reportedWidth ),
+  reportedHeight( _reportedHeight ),
+  refBufferSize( _width * _height ),
+  refBuffer( new Dali::PixelBuffer[ refBufferSize ] )
+{
+  LoadBuffer();
+}
+
+ImageDetails::~ImageDetails()
+{
+  delete [] refBuffer;
+}
+
+void ImageDetails::LoadBuffer()
+{
+  // Load the reference buffer from the buffer file
+
+  std::string refBufferFilename( name + ".buffer" );
+  FILE *fp = fopen ( refBufferFilename.c_str(), "rb" );
+  AutoCloseFile autoCloseBufferFile( fp );
+
+  if ( fp )
+  {
+    fread( refBuffer, sizeof( Dali::PixelBuffer ), refBufferSize, fp );
+  }
+}
+
+
+LoadFunctions::LoadFunctions( LoadBitmapHeaderFunction _header, LoadBitmapFunction _loader )
+: header( _header ),
+  loader( _loader )
+{
+}
+
+void TestImageLoading( const ImageDetails& image, const LoadFunctions& functions )
+{
+  FILE* fp = fopen( image.name.c_str() , "rb" );
+  AutoCloseFile autoClose( fp );
+  DALI_TEST_CHECK( fp != NULL );
+
+  // Check the header file.
+
+  unsigned int width(0), height(0);
+  const Dali::TizenPlatform::ImageLoader::Input input( fp );
+  DALI_TEST_CHECK( functions.header( input, width, height ) );
+
+  DALI_TEST_EQUALS( width,  image.reportedWidth,  TEST_LOCATION );
+  DALI_TEST_EQUALS( height, image.reportedHeight, TEST_LOCATION );
+
+  // Loading the header moves the pointer within the file so reset to start of file.
+  fseek( fp, 0, 0 );
+
+  // Create a bitmap object and store a pointer to that object so it is destroyed at the end.
+  Dali::Integration::Bitmap * bitmap = Dali::Integration::Bitmap::New( Dali::Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,  ResourcePolicy::OWNED_RETAIN  );
+  Dali::Integration::BitmapPtr bitmapPtr( bitmap );
+
+
+  // Load Bitmap and check its return values.
+  DALI_TEST_CHECK( functions.loader( StubImageLoaderClient(), input, *bitmap ) );
+  DALI_TEST_EQUALS( image.width,  bitmap->GetImageWidth(),  TEST_LOCATION );
+  DALI_TEST_EQUALS( image.height, bitmap->GetImageHeight(), TEST_LOCATION );
+
+  // Compare buffer generated with reference buffer.
+  Dali::PixelBuffer* bufferPtr( bitmapPtr->GetBuffer() );
+  Dali::PixelBuffer* refBufferPtr( image.refBuffer );
+  for ( unsigned int i = 0; i < image.refBufferSize; ++i, ++bufferPtr, ++refBufferPtr )
+  {
+    if( *bufferPtr != *refBufferPtr )
+    {
+      tet_result( TET_FAIL );
+      tet_printf("%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);
+      break;
+    }
+  }
+}
+
+void DumpImageBufferToTempFile( std::string filename, std::string targetFilename, const LoadFunctions& functions )
+{
+  FILE* fp = fopen( filename.c_str() , "rb" );
+  AutoCloseFile autoClose( fp );
+
+  Dali::Integration::Bitmap* bitmap = Dali::Integration::Bitmap::New( Dali::Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,  ResourcePolicy::OWNED_RETAIN );
+  Dali::Integration::BitmapPtr bitmapPtr( bitmap );
+  const Dali::TizenPlatform::ImageLoader::Input input( fp );
+
+  DALI_TEST_CHECK( functions.loader( StubImageLoaderClient(), input, *bitmap ) );
+
+  Dali::PixelBuffer* bufferPtr( bitmapPtr->GetBuffer() );
+
+  FILE* writeFp = fopen( targetFilename.c_str(), "wb" );
+  AutoCloseFile autoCloseWrite( writeFp );
+  fwrite( bufferPtr, 1, bitmap->GetBufferSize(), writeFp );
+}
diff --git a/automated-tests/src/dali-adaptor-internal/image-loaders.h b/automated-tests/src/dali-adaptor-internal/image-loaders.h
new file mode 100644 (file)
index 0000000..ffbb2b3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DALI_ADAPTOR_TET_IMAGE_LOADERS_H_
+#define __DALI_ADAPTOR_TET_IMAGE_LOADERS_H_
+
+#include <dali/dali.h>
+#include <dali/integration-api/bitmap.h>
+#include "platform-abstractions/tizen/resource-loader/resource-loading-client.h"
+#include "platform-abstractions/tizen/image-loaders/image-loader-input.h"
+
+// Simple structure to close the file when finished with it.
+struct AutoCloseFile
+{
+  AutoCloseFile( FILE *fp );
+  ~AutoCloseFile();
+  FILE* filePtr;
+};
+
+/// Structure to hold image details and the reference buffer.
+struct ImageDetails
+{
+  /**
+   * Normal Constructor.
+   *
+   * @param[in]  _name    The name of the image to open.  The reference buffer file should have the same name appended with ".buffer".
+   * @param[in]  _width   The width of the image.
+   * @param[in]  _height  The height of the image.
+   */
+  ImageDetails( const char * const _name, unsigned int _width, unsigned int _height );
+
+  /**
+   * Sometimes an image reports an incorrect size in the header than what it actually is. In such a
+   * scenario, this constructor should be used.
+   *
+   * @param[in]  _name            The name of the image to open.  The reference buffer file should have the same name appended with ".buffer".
+   * @param[in]  _width           The width of the image.
+   * @param[in]  _height          The height of the image.
+   * @param[in]  _reportedWidth   The reported width of the image by reading the header.
+   * @param[in]  _reportedHeight  The reported height of the image by reading the header.
+   */
+  ImageDetails( const char * const _name, unsigned int _width, unsigned int _height, unsigned int _reportedWidth, unsigned int _reportedHeight );
+
+  /**
+   * Destructor
+   */
+  ~ImageDetails();
+
+
+  std::string name;
+  unsigned int width;
+  unsigned int height;
+  unsigned int reportedWidth;
+  unsigned int reportedHeight;
+  unsigned int refBufferSize;
+  Dali::PixelBuffer* const refBuffer;
+
+private:
+
+  /**
+   * Loads the reference buffer file.
+   */
+  void LoadBuffer();
+};
+
+/**
+ * A structure storing the methods that should be called when reading an image's header and when
+ * reading the bitmap from the image file.
+ */
+struct LoadFunctions
+{
+  typedef bool (*LoadBitmapFunction)( const Dali::TizenPlatform::ResourceLoadingClient& client, const Dali::TizenPlatform::ImageLoader::Input& input, Dali::Integration::Bitmap& );
+  typedef bool (*LoadBitmapHeaderFunction)( const Dali::TizenPlatform::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+  LoadFunctions( LoadBitmapHeaderFunction _header, LoadBitmapFunction _loader );
+  LoadBitmapHeaderFunction header;
+  LoadBitmapFunction loader;
+};
+
+// Helper method to test each image file.
+/**
+ * Use this method to test the header and and bitmap loading of each image.
+ * The loaded bitmap is then checked with the reference bitmap in ImageDetails.
+ *
+ * @param[in]  image      The image details.
+ * @param[in]  functions  The loader functions that need to be called.
+ */
+void TestImageLoading( const ImageDetails& image, const LoadFunctions& functions );
+
+/**
+ * Helper function which should be used when first creating a reference buffer file.
+ * Set output file to a file in the /tmp/ directory e.g:
+ *   DumpImageBufferToTempFile( "images/pattern.gif" , "/tmp/pattern.gif.buffer" );
+ *
+ * @param[in]  filename        The path of the image file.
+ * @param[in]  targetFilename  The path of where the buffer should be written to.  This should ideally be in the "/tmp" folder.
+ * @param[in]  functions       The loader functions to call.
+ */
+void DumpImageBufferToTempFile( std::string filename, std::string targetFilename, const LoadFunctions& functions );
+
+#endif // __DALI_ADAPTOR_TET_IMAGE_LOADERS_H_
diff --git a/automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp b/automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp
new file mode 100644 (file)
index 0000000..bc6bf8f
--- /dev/null
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-adaptor-internal-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "r";
+  bool optRerunFailed(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'r':
+        optRerunFailed = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-ConditionalWait.cpp b/automated-tests/src/dali-adaptor-internal/utc-ConditionalWait.cpp
new file mode 100644 (file)
index 0000000..f66562d
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dali-test-suite-utils.h>
+#include "conditional-wait.h"
+
+using Dali::Internal::Adaptor::ConditionalWait;
+
+namespace // for local variables to avoid name clashes
+{
+volatile int gGlobalValue = 0;
+volatile bool gWorkerThreadWait = true;
+enum ThreadState { INIT, RUN, TERMINATE } volatile gWorkerThreadState = INIT;
+ConditionalWait* volatile gConditionalWait; // volatile pointer to a ConditionalWait object
+}
+
+void* WorkerThreadNotify( void* ptr )
+{
+  gGlobalValue = -1;
+  while( gWorkerThreadWait ) // wait till we can exit
+  {
+    gWorkerThreadState = RUN;
+    usleep( 1 ); // 1 microseconds
+  }
+  usleep( 200 ); // give other thread time to get to Wait
+  gGlobalValue = 1;
+  gConditionalWait->Notify();
+  gWorkerThreadState = TERMINATE;
+  return NULL;
+}
+
+int UtcConditionalWait1P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario:  wait - notify with 2 threads");
+
+  pthread_t thread1;
+  // initialize values
+  gConditionalWait = new ConditionalWait();
+  gWorkerThreadWait = true;
+  DALI_TEST_EQUALS( INIT, gWorkerThreadState, TEST_LOCATION );
+  DALI_TEST_EQUALS( 0, gGlobalValue, TEST_LOCATION );
+
+  pthread_create( &thread1, NULL, &WorkerThreadNotify, NULL );
+  // wait till the thread is in run state
+  while( RUN != gWorkerThreadState )
+  {
+    usleep( 1 ); // 1 microsecond
+  }
+  // let worker continue and finish
+  gWorkerThreadWait = false;
+  gConditionalWait->Wait();
+  DALI_TEST_EQUALS( 1, gGlobalValue, TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+
+  // wait till the thread is terminated state
+  while( TERMINATE != gWorkerThreadState )
+  {
+    usleep( 1 ); // 1 microsecond
+  }
+
+  void* exitValue;
+  pthread_join( thread1, &exitValue );
+
+  delete gConditionalWait;
+  END_TEST;
+}
+
+int UtcConditionalWait2P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario: notify without wait");
+
+  ConditionalWait wait;
+  DALI_TEST_EQUALS( 0u, wait.GetWaitCount(), TEST_LOCATION );
+  wait.Notify();
+  DALI_TEST_EQUALS( 0u, wait.GetWaitCount(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+volatile int gNotifyCount = 0;
+void* WorkerThreadNotifyN( void* ptr )
+{
+  while( gNotifyCount > 0 )
+  {
+    gConditionalWait->Notify();
+    usleep( 10 ); // 10 microseconds between each notify
+  }
+  return NULL;
+}
+
+int UtcConditionalWait3P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario: wait - notify N times 2 threads");
+
+  // initialize values
+  gConditionalWait = new ConditionalWait();
+  gNotifyCount = 100;
+
+  pthread_t thread1;
+  pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
+
+  while( gNotifyCount > 0 )
+  {
+    gConditionalWait->Wait();
+    --gNotifyCount;
+    DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+    usleep( 10 ); // 10 microseconds between each notify
+  }
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+
+  void* exitValue;
+  pthread_join( thread1, &exitValue );
+
+  delete gConditionalWait;
+  END_TEST;
+}
+
+int UtcConditionalWait4P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario:  wait - notify N times from 3 threads");
+
+  // initialize values
+  gConditionalWait = new ConditionalWait();
+  gNotifyCount = 100;
+
+  pthread_t thread1;
+  pthread_create( &thread1, NULL, &WorkerThreadNotifyN, NULL );
+  pthread_t thread2;
+  pthread_create( &thread2, NULL, &WorkerThreadNotifyN, NULL );
+  pthread_t thread3;
+  pthread_create( &thread3, NULL, &WorkerThreadNotifyN, NULL );
+
+  while( gNotifyCount > 0 )
+  {
+    gConditionalWait->Wait();
+    --gNotifyCount;
+    DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+    usleep( 10 ); // 10 microseconds between each notify
+  }
+
+  void* exitValue;
+  pthread_join( thread1, &exitValue );
+  pthread_join( thread2, &exitValue );
+  pthread_join( thread3, &exitValue );
+
+  delete gConditionalWait;
+  END_TEST;
+}
+
+void* WorkerThreadWaitN( void* ptr )
+{
+  gConditionalWait->Wait();
+
+  return NULL;
+}
+
+int UtcConditionalWait5P(void)
+{
+  tet_infoline("Testing ConditionalWait - scenario:  4 threads wait - notify once from 1 thread");
+
+  // initialize values
+  gConditionalWait = new ConditionalWait();
+
+  pthread_t thread1;
+  pthread_create( &thread1, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread2;
+  pthread_create( &thread2, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread3;
+  pthread_create( &thread3, NULL, &WorkerThreadWaitN, NULL );
+  pthread_t thread4;
+  pthread_create( &thread4, NULL, &WorkerThreadWaitN, NULL );
+
+  // wait till all child threads are waiting
+  while( gConditionalWait->GetWaitCount() < 4 )
+  { }
+
+  // notify once, it will resume all threads
+  gConditionalWait->Notify();
+
+  void* exitValue;
+  pthread_join( thread1, &exitValue );
+  pthread_join( thread2, &exitValue );
+  pthread_join( thread3, &exitValue );
+  pthread_join( thread4, &exitValue );
+
+  DALI_TEST_EQUALS( 0u, gConditionalWait->GetWaitCount(), TEST_LOCATION );
+
+  delete gConditionalWait;
+  END_TEST;
+}
+
+int UtcConditionalWaitNonCopyable(void)
+{
+  // we want to make sure that ConditionalWait is not copyable (its copy constructor is not defined)
+  // this test will stop compiling if ConditionalWait has compiler generated copy constructor
+  DALI_COMPILE_TIME_ASSERT( !__has_trivial_copy( ConditionalWait ) );
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp
new file mode 100644 (file)
index 0000000..f67594c
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <dali/dali.h>
+#include <command-line-options.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::Internal::Adaptor;
+
+
+// Called only once before first test is run.
+void command_line_options_startup(void)
+{
+  test_return_value = TET_UNDEF;
+  optind = 0; // Reset opt for test
+}
+
+// Called only once after last test is run
+void command_line_options_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliCommandLineOptionsNoArgs(void)
+{
+  optind=0;
+
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.noVSyncOnRender, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageWidth, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliShortArgs(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "-w", "800",
+      "-h", "1000",
+      "-d", "4x5",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.noVSyncOnRender, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "4x5", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliLongArgsEqualsSign(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width=800",
+      "--height=1000",
+      "--dpi=3x4",
+      "--no-vsync",
+      "--help"
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.noVSyncOnRender, 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliLongArgsSpaces(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width", "800",
+      "--height", "1000",
+      "--dpi", "3x4",
+      "--no-vsync",
+      "--help"
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.noVSyncOnRender, 1, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsNonDaliArgs(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "hello-world",
+      "-y", "600",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 4, TEST_LOCATION );
+
+  // Ensure order has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixture(void)
+{
+  optind = 0; // Reset opt for test
+
+  const char* argList[] =
+  {
+    "program",
+    "--width=800",
+    "hello-world",
+    "-y", "600",
+    "--height", "1000",
+    "-r",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixtureDaliOpsAtStart(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width=800",
+      "--height", "1000",
+      "-r",
+      "hello-world",
+      "-y", "600",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "-r", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "600", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixtureDaliOpsAtEnd(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "hello-world",
+      "-y", "600",
+      "-r",
+      "--width=800",
+      "--height", "1000",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp
new file mode 100644 (file)
index 0000000..fdb1df5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/internal/text-abstraction/font-client-helper.h>
+
+using namespace Dali;
+
+int UtcDaliFontClient(void)
+{
+  const int ORDERED_VALUES[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
+
+  const unsigned int NUM_OF_ORDERED_VALUES = sizeof( ORDERED_VALUES ) / sizeof( int );
+
+  TestApplication application;
+  int preciseIndex = 0;
+  int result=0;
+
+  tet_infoline("UtcDaliFontClient center range");
+  preciseIndex = 4;
+  result = TextAbstraction::Internal::ValueToIndex( ORDERED_VALUES[preciseIndex], ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( preciseIndex, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient start of range");
+  preciseIndex = 0;
+  result = TextAbstraction::Internal::ValueToIndex( ORDERED_VALUES[preciseIndex], ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( preciseIndex, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient end of range");
+  preciseIndex = 8;
+  result = TextAbstraction::Internal::ValueToIndex( ORDERED_VALUES[preciseIndex], ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( preciseIndex, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient below of range");
+  result = TextAbstraction::Internal::ValueToIndex( 30, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 0, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient below of range");
+  result = TextAbstraction::Internal::ValueToIndex( 220, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 8, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient zero ");
+  result = TextAbstraction::Internal::ValueToIndex( 0, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 0, result, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp
new file mode 100644 (file)
index 0000000..1093287
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-test-suite-utils.h>
+
+#include "platform-abstractions/tizen/image-loaders/loader-gif.h"
+#include "image-loaders.h"
+
+using namespace Dali;
+
+namespace {
+static const LoadFunctions GifLoaders( TizenPlatform::LoadGifHeader, TizenPlatform::LoadBitmapFromGif );
+}
+
+
+void gif_loader_startup(void)
+{
+}
+
+void gif_loader_cleanup(void)
+{
+}
+
+int UtcDaliGifLoaderInterlaced(void)
+{
+  ImageDetails interlaced( TEST_IMAGE_DIR "/interlaced.gif", 365u, 227u );
+  TestImageLoading( interlaced, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderErrorBits(void)
+{
+  ImageDetails errorBits( TEST_IMAGE_DIR "/error-bits.gif", 534u, 749u, 1280u, 1024u );
+  TestImageLoading( errorBits, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderPattern(void)
+{
+  ImageDetails pattern( TEST_IMAGE_DIR "/pattern.gif", 600u, 600u );
+  TestImageLoading( pattern, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderTransparency(void)
+{
+  ImageDetails transparency( TEST_IMAGE_DIR "/transparency.gif", 320u, 280u );
+  TestImageLoading( transparency, GifLoaders );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp
new file mode 100644 (file)
index 0000000..37d1a9e
--- /dev/null
@@ -0,0 +1,1524 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-test-suite-utils.h>
+#include "platform-abstractions/portable/image-operations.h"
+#include <dali/devel-api/common/ref-counted-dali-vector.h>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+using namespace Dali::Internal::Platform;
+
+namespace
+{
+
+/**
+ * @brief Generate a random integer between zero and the parameter passed in.
+ **/
+uint32_t RandomInRange( uint32_t max )
+{
+  const uint32_t randToMax = lrand48() % (max + 1);
+  return randToMax;
+}
+
+/**
+ * @brief Random number representable in an 8 bit color component.
+ */
+inline uint32_t RandomComponent8()
+{
+  return RandomInRange( 255u );
+}
+
+/**
+ * @brief Random number representable in a 5 bit color component.
+ */
+inline uint32_t RandomComponent5()
+{
+  return RandomInRange( 31u );
+}
+
+/**
+ * @brief Random number representable in a 6 bit color component.
+ */
+inline uint32_t RandomComponent6()
+{
+  return RandomInRange( 63u );
+}
+
+/**
+ * @brief RGBA8888 Pixels from separate color components.
+ */
+inline uint32_t PixelRGBA8888( uint32_t r, uint32_t g, uint32_t b, uint32_t a )
+{
+  return (r << 24) + (g << 16) + (b << 8) + a;
+}
+
+/**
+ * @brief RGB565 Pixels from color components in the low bits of passed-in words.
+ */
+inline uint16_t PixelRGB565( uint32_t r, uint32_t g, uint32_t b )
+{
+  return (r << 11) + (g << 5) + b;
+}
+
+/**
+ * @brief RGBA8888 Pixels with random color components.
+ */
+inline uint32_t RandomPixelRGBA8888( )
+{
+  const uint32_t randomPixel = PixelRGBA8888( RandomComponent8(), RandomComponent8(), RandomComponent8(), RandomComponent8() );
+  return randomPixel;
+}
+
+/**
+ * @brief Return a hash over a set of pixels.
+ *
+ * Used to check a buffer of pixels is unmodified by an operation given inputs
+ * that should mean that it is not changed.
+ */
+inline uint32_t HashPixels( const uint32_t* const pixels, unsigned int numPixels )
+{
+  uint32_t hash = 5381;
+
+  for( unsigned int i = 0; i < numPixels; ++i )
+  {
+    hash = hash * 33 + pixels[i];
+  }
+
+  return hash;
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTestsRGBA8888( size_t scanlineLength, Dali::Vector<uint32_t>& scanline, Dali::Vector<uint32_t>& reference )
+{
+  scanline.Resize( scanlineLength );
+  reference.Reserve( scanlineLength / 2 + 32 );
+
+  // Prepare some random pixels:
+  srand( 19 * 23 * 47 * 53 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent8();
+    const uint32_t red2   = RandomComponent8();
+    const uint32_t green1 = RandomComponent8();
+    const uint32_t green2 = RandomComponent8();
+    const uint32_t blue1  = RandomComponent8();
+    const uint32_t blue2  = RandomComponent8();
+    const uint32_t alpha1 = RandomComponent8();
+    const uint32_t alpha2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = PixelRGBA8888( red1, green1, blue1, alpha1 );
+    scanline[i * 2 + 1] = PixelRGBA8888( red2, green2, blue2, alpha2 );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGBA8888( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u ) );
+  }
+
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEEEEEEEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTestsRGB565( size_t scanlineLength, Dali::Vector<uint16_t>& scanline, Dali::Vector<uint16_t>& reference )
+{
+  scanline.Resize( scanlineLength );
+  reference.Reserve( scanlineLength / 2 + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent5();
+    const uint32_t red2   = RandomComponent5();
+    const uint32_t green1 = RandomComponent6();
+    const uint32_t green2 = RandomComponent6();
+    const uint32_t blue1  = RandomComponent5();
+    const uint32_t blue2  = RandomComponent5();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = PixelRGB565( red1, green1, blue1 );
+    scanline[i * 2 + 1] = PixelRGB565( red2, green2, blue2 );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGB565( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u ) );
+  }
+
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEEEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTests2Bytes( size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference )
+{
+  scanline.Resize( scanlineLength * 2 );
+  reference.Reserve( scanlineLength + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 * 59 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t c11   = RandomComponent8();
+    const uint32_t c12   = RandomComponent8();
+    const uint32_t c21   = RandomComponent8();
+    const uint32_t c22   = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 4]     = c11;
+    scanline[i * 4 + 1] = c12;
+    scanline[i * 4 + 2] = c21;
+    scanline[i * 4 + 3] = c22;
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( (c11 + c21) >> 1u );
+    reference.PushBack( (c12 + c22) >> 1u );
+  }
+
+  for( size_t i = scanlineLength; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEE;
+  }
+}
+
+/**
+ * @brief Build some dummy 1 byte per pixel scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTests1Byte( size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference )
+{
+  scanline.Resize( scanlineLength * 2 );
+  reference.Reserve( scanlineLength + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 * 63 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t c1 = RandomComponent8();
+    const uint32_t c2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = c1;
+    scanline[i * 2 + 1] = c2;
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( (c1 + c2) >> 1u );
+
+  }
+
+  for( size_t i = scanlineLength; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise vertical averaging code on.
+ *
+ * All tested formats bar RGB565 can share this setup.
+ */
+void SetupScanlinesRGBA8888( size_t scanlineLength, Dali::Vector<uint32_t>& scanline1, Dali::Vector<uint32_t>& scanline2, Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output )
+{
+  scanline1.Reserve( scanlineLength );
+  scanline2.Reserve( scanlineLength );
+  reference.Reserve( scanlineLength + 32 );
+  output.Reserve( scanlineLength + 32 );
+
+  for( size_t i = scanlineLength; i < output.Capacity(); ++i )
+  {
+    output[i]    = 0xDEADBEEF;
+    reference[i] = 0xDEADBEEF;
+  }
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 );
+  for( size_t i = 0; i < scanlineLength; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent8();
+    const uint32_t red2   = RandomComponent8();
+    const uint32_t green1 = RandomComponent8();
+    const uint32_t green2 = RandomComponent8();
+    const uint32_t blue1  = RandomComponent8();
+    const uint32_t blue2  = RandomComponent8();
+    const uint32_t alpha1 = RandomComponent8();
+    const uint32_t alpha2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline1.PushBack( PixelRGBA8888( red1, green1, blue1, alpha1 ) );
+    scanline2.PushBack( PixelRGBA8888( red2, green2, blue2, alpha2 ) );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGBA8888( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u ) );
+  }
+}
+
+/**
+ * @brief Compares a scanline of interest to a reference, testing each pixel is the same.
+ */
+void MatchScanlinesRGBA8888( Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output, size_t& numMatches, const char * const location )
+{
+  numMatches = 0;
+  for( size_t i = 0, length = reference.Capacity(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( output[i], reference[i], location );
+    numMatches += output[i] == reference[i];
+  }
+}
+
+} //< namespace unnamed
+
+/**
+ * @brief Test component averaging code.
+ */
+int UtcDaliImageOperationsAverageComponent(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 1u, 1u ), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0xffffffffu >> 1u, 0xffffffffu >> 1u ), 0xffffffffu >> 1u, TEST_LOCATION );
+  const unsigned int avg3 = Dali::Internal::Platform::AverageComponent( 0xfffffffeu, 1u );
+  DALI_TEST_EQUALS( avg3, 0x7fffffffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 255u, 255u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 512u, 0u ), 256u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 511u, 0u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 510u, 0u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 509u, 0u ), 254u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0u, 509u ), 254u, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Test Pixel averaging code.
+ */
+int UtcDaliImageOperationsAveragePixelRGBA8888(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0x01010101, 0x01010101 ), 0x01010101u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0x01010101, 0x03030303 ), 0x02020202u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0xffffffff, 0xffffffff ), 0xffffffffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0xffffffff, 0u ), 0x7f7f7f7fu, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Test RGBA565 pixel averaging function.
+ */
+int UtcDaliImageOperationsAveragePixelRGB565(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0xf800u ), 0xf800u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0x800u ), 1u << 15, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x7e0u, 0x7e0u ), 0x7e0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x7e0u, 0x20u ), 1u << 10, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x1f, 0x1f ), 0x1fu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x1f, 0x1 ), 1u << 4, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0x7e0u ), 0x7800u + 0x3e0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xffff, 0xffff ), 0xffffu, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Build a square bitmap, downscale it and assert the resulting bitmap has the right dimensions.
+ */
+void TestDownscaledBitmapHasRightDimensionsAndFormat(
+    Pixel::Format format,
+    uint32_t sourceDimension,
+    uint32_t targetDimension,
+    uint32_t expectedDimension,
+    const char * const location )
+{
+  ImageDimensions desired( targetDimension, targetDimension );
+  FittingMode::Type fittingMode( FittingMode::SHRINK_TO_FIT );
+  SamplingMode::Type samplingMode( SamplingMode::BOX );
+
+  Integration::BitmapPtr sourceBitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+  sourceBitmap->GetPackedPixelsProfile()->ReserveBuffer( format, sourceDimension, sourceDimension, sourceDimension, sourceDimension );
+
+  Integration::BitmapPtr downScaled = DownscaleBitmap( *sourceBitmap, desired, fittingMode, samplingMode );
+
+  DALI_TEST_EQUALS( downScaled->GetImageWidth(), expectedDimension, location );
+  DALI_TEST_EQUALS( downScaled->GetImageHeight(), expectedDimension, location );
+  DALI_TEST_EQUALS( downScaled->GetPixelFormat(), format, location );
+}
+
+/**
+ * @brief Test the top-level function for reducing the dimension of a bitmap,
+ * feeding it each of the five pixel formats that are output by image loaders.
+ * Simply assert that the resulting bitmaps have the expected dimensions and
+ * formats.
+ */
+int UtcDaliImageOperationsDownscaleBitmap(void)
+{
+  // Do Scalings that are expected to work for all pixels modes and assert the resulting bitmap dimensions:
+
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 1024, 8, 8, TEST_LOCATION );
+
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 773, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 787, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 797, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 809, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 811, 1, 1, TEST_LOCATION );
+
+  // Do Scalings that are expected to produce a slightly larger than requested image:
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 47, 7, 11, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 73, 17, 18, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 61, 8, 15, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 19, 5, 9, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 353, 23, 44, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test downscaling of RGB888 images as raw pixel arrays.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
+{
+  unsigned outWidth = -1, outHeight = -1;
+
+  // Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced:
+
+  // Scale down a black/white checkerboard to mid-grey:
+  unsigned char check_4x4 [16 * 3] = {
+      0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,
+      0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff
+  };
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( check_4x4[0], 0x7f, TEST_LOCATION );
+
+  // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
+  unsigned char single_4x4 [16 * 3] = {
+    0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00
+  };
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( single_4x4[0], 0xf, TEST_LOCATION );
+
+  // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
+  // (white pixel at bottom-right of image)
+  unsigned char single_4x4_2 [16 * 3] = {
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff
+    };
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( single_4x4_2[0], 0xf, TEST_LOCATION );
+
+  // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
+
+  unsigned char magenta_600_x_600[608*608 * 3];
+  for( unsigned int i = 0; i < sizeof(magenta_600_x_600); i += 3 )
+  {
+    magenta_600_x_600[i] = 0xff;
+    magenta_600_x_600[i + 1] = 0;
+    magenta_600_x_600[i + 2] = 0xff;
+  }
+
+  // Scaling to 0 x 0 should stop at 1 x 1:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+
+  // Scaling to 1 x 1 should hit 1 x 1:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+
+  // Scaling to original dimensions should NOP:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 384u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 384u, TEST_LOCATION );
+
+  // More dimension tests:
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 44u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 44u, TEST_LOCATION );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 48u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 48u, TEST_LOCATION );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 3u && outHeight == 3u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 5u && outHeight == 5u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 7u && outHeight == 7u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 11u && outHeight == 11u );
+
+  // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
+  unsigned int numNonMagenta = 0u;
+  for( unsigned i = 0; i < sizeof(magenta_600_x_600); i += 3 )
+  {
+    numNonMagenta += magenta_600_x_600[i] == 0xff && magenta_600_x_600[i + 1] == 0x00 && magenta_600_x_600[i + 2] == 0xff ? 0 : 1;
+  }
+  DALI_TEST_EQUALS( numNonMagenta, 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that resizing RGBA8888 images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsRGBA8888( uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
+      reinterpret_cast<unsigned char *> (pixels),
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing RGB565 images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsRGB565( uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
+      reinterpret_cast<unsigned char *> (pixels),
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing 2-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensions2ComponentPair( uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
+      pixels,
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing single-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsSingleComponent( uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
+      pixels,
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test downscaling of RGBA8888 images in raw image arrays.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void)
+{
+  uint32_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xffffffff;
+  }
+  unsigned char* const pixels = reinterpret_cast<unsigned char *> (image);
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+
+  // Test downscaling where the input size is an exact multiple of the desired size:
+  // (We expect a perfect result here)
+
+  DownscaleInPlacePow2RGBA8888( pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 75u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 75u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 16u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 16u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 16u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 2u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 4u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 64u, TEST_LOCATION );
+
+  // Test downscaling where the input size is slightly off being an exact multiple of the desired size:
+  // (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
+
+  DownscaleInPlacePow2RGBA8888( pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 75u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 75u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 23u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 11u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 3u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 7u, TEST_LOCATION );
+
+  // Test downscales with source dimensions which are under a nice power of two by one:
+
+  // The target is hit exactly due to losing spare columns or rows at each iteration:
+  DownscaleInPlacePow2RGBA8888( pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 3u, TEST_LOCATION );
+
+  // Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small.
+  DownscaleInPlacePow2RGBA8888( pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 3u, TEST_LOCATION );
+
+  // Should stop at almost twice the requested dimensions:
+  DownscaleInPlacePow2RGBA8888( pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 63u, TEST_LOCATION );
+
+  // Test downscales to 1 in one or both dimensions:
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     512,     1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      16,        1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      7,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      7,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      5,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      3,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         1,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         16,        1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         3,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      33,      1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 17*19,   17*19,   1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      33,      3,         1,         4,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      9,       3,         1,         4,          1,         TEST_LOCATION );
+
+
+
+  // Test downscales to zero in one or both dimensions:
+  // Scaling should stop when one or both dimensions reach 1.
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     512,     0,         0,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     256,     0,         0,         2,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     128,     0,         0,         4,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     16,      0,         0,         32,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 128,     512,     0,         0,         1,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     0,         0,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 8,       512,     0,         0,         1,          64,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 2,       512,     0,         0,         1,          256,       TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test downscalings of RGBA8888 images in raw image arrays that should have no effect on the input.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
+{
+  uint32_t image[608*608];
+  const uint32_t numPixels = sizeof(image) / sizeof(image[0]);
+  for( unsigned i = 0; i < numPixels; ++i )
+  {
+    image[i] = RandomPixelRGBA8888();
+  }
+  const uint32_t imageHash = HashPixels( image, numPixels );
+  unsigned char* const pixels = reinterpret_cast<unsigned char *> (image);
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+
+  // Test downscales to the same size:
+  // The point is just to be sure the downscale is a NOP in this case:
+
+  DownscaleInPlacePow2RGBA8888( pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 600u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 600u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 512u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 128u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 17u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 1001u, TEST_LOCATION );
+
+  // Test downscales that request a larger size (we never upscale so these are NOPs too):
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 300,     300,     600,       600,       300,        300,       TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 3,       127,     99,        599,       3,          127,       TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 600,     600,     999,       999,       600,        600,       TEST_LOCATION ); //< checks no out of bounds mem access in this case
+
+
+  // Make sure that none of these NOP downscalings has affected the pixels of the image:
+  DALI_TEST_EQUALS( HashPixels( image, numPixels ), imageHash, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using RGB565 images in raw image
+ * arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
+{
+  // Test that calling with null and zero parameters doesn't blow up:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2RGB565( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  uint16_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xffff;
+  }
+
+  // Do a straightforward test using an exact divisor target size:
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600, 600, 75, 75, 75, 75, TEST_LOCATION );
+  // Test that a slightly smaller than possible to achieve target results in the
+  // next-higher exact divisor output image dimensions:
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600, 600, 71, 69, 75, 75, TEST_LOCATION );
+  // Test that resizing from a starting size that is slightly larger than an exact
+  // multiple of the desired dimensions still results in the desired ones being
+  // reached:
+  // Parameters:                                       input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600 + 1, 600 + 1, 75,        75,        75,         75,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 1, 512 + 1, 2,         4,         2,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 1, 128 + 1, 16,        4,         16,         4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 1, 64  + 1, 16,        2,         16,         2,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 3, 512 + 3, 16,        16,        16,         16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 3, 256 + 3, 16,        8,         16,         8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 3, 512 + 3, 4,         8,         4,          8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 7, 512 + 7, 4,         8,         4,          8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 7, 512 + 7, 2,         4,         2,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 7, 128 + 7, 16,        4,         16,         4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 7, 64  + 7, 16,        2,         16,         2,         TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using 2-byte-per-pixel images in
+ * raw image arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
+{
+  // Simple test that a null pointer does not get dereferenced in the function:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2ComponentPair( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  // Simple tests of dimensions output:
+
+  uint8_t image[608*608*2];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xff;
+  }
+
+  TestDownscaleOutputsExpectedDimensions2ComponentPair( image,
+                                                        600, 600, //< Input dimensions
+                                                        37, 37,   //< Requested dimensions
+                                                        37, 37,   //< Expected output dimensions
+                                                        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensions2ComponentPair( image,
+                                                        600, 600, //< Input dimensions
+                                                        34, 35,   //< Requested dimensions to scale-down to
+                                                        37, 37,   //< Expected output dimensions achieved
+                                                        TEST_LOCATION );
+  ///@note: No need to be as comprehensive as with RGB888 and RGBA8888 as the logic is shared.
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using 1-byte-per-pixel images in
+ * raw image arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
+{
+  // Simple test that a null pointer does not get dereferenced in the function:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2SingleBytePerPixel( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  // Tests of output dimensions from downscaling:
+  uint8_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xff;
+  }
+
+  TestDownscaleOutputsExpectedDimensionsSingleComponent( image,
+                                                         600, 300,  //< Input dimensions
+                                                         150, 75,   //< Requested dimensions to scale-down to
+                                                         150, 75,   //< Expected output dimensions achieved
+                                                         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsSingleComponent( image, 577, 411, 142, 99, 144, 102, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGB888(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven[] =    { 0xff, 0, 0,   0, 0xff, 0xff,   0xff, 0, 0,   0, 0xff, 0xff };
+  unsigned char shortOdd[] =     { 0xff, 0, 0,  0, 0xff, 0xff,  0xff, 0, 0,  0, 0xff, 0xff,  0xC, 0xC, 0xC };
+
+  Dali::Internal::Platform::HalveScanlineInPlaceRGB888( shortEven, 4u );
+  Dali::Internal::Platform::HalveScanlineInPlaceRGB888( shortOdd, 4u );
+  for( unsigned i = 0; i < sizeof(shortEven) >> 1u ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(shortEven[i]), 0x7fu, TEST_LOCATION );
+    DALI_TEST_EQUALS( unsigned(shortOdd[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGBA8888(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline;
+  Dali::Vector<uint32_t> reference;
+  SetupScanlineForHalvingTestsRGBA8888( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlaceRGBA8888( (uint8_t *) &scanline[0], scanlineLength );
+
+  // Check that the halving matches the independently calculated reference:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( scanline[i], reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  // Test for no beyond-bounds writes:
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    DALI_TEST_EQUALS( reference[i],  0xEEEEEEEE, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGB565(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint16_t> scanline;
+  Dali::Vector<uint16_t> reference;
+  SetupScanlineForHalvingTestsRGB565( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlaceRGB565( (unsigned char *) (&scanline[0]), scanlineLength );
+
+  // Check output against reference:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( scanline[i], reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  // Test for no beyond-bounds writes:
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    DALI_TEST_EQUALS( reference[i],  0xEEEE, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlace2Bytes(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint8_t> scanline;
+  Dali::Vector<uint8_t> reference;
+  SetupScanlineForHalvingTests2Bytes( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlace2Bytes( &scanline[0], scanlineLength );
+
+  // Test the output against the reference (no differences):
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( 1u * scanline[i], 1u * reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  // The number of matching bytes should be double the number of pixels, which happens to be the original scanline length in pixels:
+  DALI_TEST_EQUALS( numMatches, scanlineLength, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint8_t> scanline;
+  Dali::Vector<uint8_t> reference;
+  SetupScanlineForHalvingTests1Byte( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlace1Byte( &scanline[0], scanlineLength );
+
+  // Test the reference matches the output:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( 1u * scanline[i], 1u * reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines1(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines1( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) );
+  for( unsigned i = 0; i < sizeof(shortEven1) ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines1( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 4 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of 2-byte-per-pixel pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines2(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines2( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 2 );
+
+  for( unsigned i = 0; i < sizeof(shortEven1); ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines2( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 2 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGB888 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines3(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines3( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 3 );
+  for( unsigned i = 0; i < sizeof(shortEven1) ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 3 * 4 * 90u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines3( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 4 / 3 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGBA8888 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlinesRGBA8888(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlinesRGBA8888( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGB565 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlinesRGB565(void)
+{
+  // Red and cyan, averaging to grey:
+  const uint16_t shortEven1[] =    { 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xBEEF, 0xBEEF };
+  const uint16_t shortEven2[] =    { 0x7ff,  0x7ff,  0x7ff,  0x7ff,  0x7ff,  0x7ff, 0xBEEF, 0xBEEF };
+  const size_t arrayLength = sizeof(shortEven1) / sizeof(shortEven1[0]) - 2;
+  uint16_t outputBuffer[arrayLength + 2];
+  outputBuffer[arrayLength] = 0xDEAD;
+  outputBuffer[arrayLength+1] = 0xDEAD;
+
+  Dali::Internal::Platform::AverageScanlinesRGB565( (const unsigned char*) shortEven1, (const unsigned char*) shortEven2, (unsigned char*) outputBuffer,  arrayLength );
+  for( unsigned i = 0; i <  arrayLength ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0xffff - (1u << 15) - (1u << 10) - (1u << 4), TEST_LOCATION );
+  }
+
+  // Check for buffer overrun:
+  DALI_TEST_EQUALS( outputBuffer[arrayLength], 0xDEAD, TEST_LOCATION );
+  DALI_TEST_EQUALS( outputBuffer[arrayLength+1], 0xDEAD, TEST_LOCATION );
+
+  END_TEST;
+}
+
+namespace
+{
+
+void MakeSingleColorImageRGBA8888( unsigned int width, unsigned int height, uint32_t *inputImage )
+{
+  const uint32_t inPixel = PixelRGBA8888( 255, 192, 128, 64 );
+  for( unsigned int i = 0; i < width * height; ++i )
+  {
+    inputImage[i] = inPixel;
+  }
+}
+
+/**
+ * @brief Allocate an image buffer with protected pages to top and tail it and
+ * SEGV if an operation strays into them.
+ */
+void MakeGuardedOutputImageRGBA8888( unsigned int desiredWidth,  unsigned int desiredHeight, uint32_t *& outputBuffer, uint32_t *& outputImage )
+{
+  const size_t outputBufferSize = getpagesize() + sizeof(uint32_t) * desiredWidth * desiredHeight + getpagesize();
+  outputBuffer = (uint32_t *) valloc( outputBufferSize );
+  mprotect( outputBuffer, getpagesize(), PROT_READ );
+  mprotect( ((char*) outputBuffer) + outputBufferSize - getpagesize(), getpagesize(), PROT_READ );
+  outputImage = outputBuffer + getpagesize() / sizeof(outputBuffer[0]);
+}
+
+/**
+ * @brief Allocate a buffer of pages that are read-only, that is big enough for the number of pixels passed-in.
+ */
+uint32_t* AllocateReadOnlyPagesRGBA( unsigned int numPixels )
+{
+  const unsigned int numWholePages = (numPixels * sizeof(uint32_t)) / getpagesize();
+  bool needExtraPage = (numPixels * sizeof(uint32_t)) % getpagesize() != 0;
+  const size_t outputBufferSize = (numWholePages + (needExtraPage ? 1 : 0)) * getpagesize();
+  uint32_t * outputBuffer = (uint32_t *) valloc( outputBufferSize );
+  mprotect( outputBuffer, outputBufferSize, PROT_READ );
+
+  return outputBuffer;
+}
+
+/**
+ * @brief Free a buffer of pages that are read-only.
+ */
+void FreeReadOnlyPagesRGBA( uint32_t * pages, unsigned int numPixels )
+{
+  const size_t bufferSize = numPixels * 4;
+  mprotect( pages, bufferSize, PROT_READ | PROT_WRITE );
+  free( pages );
+}
+
+/*
+ * @brief Make an image with a checkerboard pattern.
+ * @note This is an easy pattern to scan for correctness after a downscaling test.
+ */
+Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888( unsigned int width,  unsigned int height, unsigned int checkerSize )
+{
+  const unsigned int imageWidth = width * checkerSize;
+  const unsigned int imageHeight = height * checkerSize;
+  Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = new Dali::RefCountedVector<uint32_t>;
+  image->GetVector().Resize( imageWidth * imageHeight );
+
+  uint32_t rowColor = 0xffffffff;
+  for( unsigned int cy = 0; cy < height; ++cy )
+  {
+    rowColor = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
+    uint32_t checkColor = rowColor;
+    for( unsigned int cx = 0; cx < width; ++cx )
+    {
+      checkColor = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
+      uint32_t paintedColor = checkColor;
+      // Draw 3 special case checks as r,g,b:
+      if(cx == 0 && cy == 0)
+      {
+        paintedColor = 0xff0000ff;// Red
+      }
+      else if(cx == 7 && cy == 0)
+      {
+        paintedColor = 0xff00ff00;// Green
+      }
+      else if(cx == 7 && cy == 7)
+      {
+        paintedColor = 0xffff0000;// blue
+      }
+      uint32_t * check = &image->GetVector()[ (cy * checkerSize * imageWidth) + (cx * checkerSize)];
+      for( unsigned int py = 0; py < checkerSize; ++py )
+      {
+        uint32_t * checkLine = check +  py * imageWidth;
+        for( unsigned int px = 0; px < checkerSize; ++px )
+        {
+          checkLine[px] = paintedColor;
+        }
+      }
+    }
+  }
+
+  return image;
+}
+
+}
+
+/**
+ * @brief Test that a scaling doesn't stray outside the bounds of the destination image.
+ *
+ * The test allocates a destination buffer that is an exact multiple of the page size
+ * with guard pages at either end.
+ */
+int UtcDaliImageOperationsPointSampleRGBA888InBounds(void)
+{
+  const unsigned int inputWidth = 163;
+  const unsigned int inputHeight = 691;
+  const unsigned int destinationBufferSize = 4096 * 4;
+  const unsigned int desiredWidth = 64;
+  const unsigned int desiredHeight = destinationBufferSize / desiredWidth; // (256)
+
+  uint32_t inputImage[ inputWidth * inputHeight ];
+
+  // Allocate an output image buffer with read-only guard pages at either end:
+  // The test will segfault if it strays into the guard pages.
+  uint32_t *outputBuffer, *outputImage;
+  MakeGuardedOutputImageRGBA8888( desiredWidth, desiredHeight, outputBuffer, outputImage );
+
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, inputWidth, inputHeight, (unsigned char*) outputImage, desiredWidth, desiredHeight );
+
+  FreeReadOnlyPagesRGBA( outputBuffer, desiredWidth * desiredHeight );
+
+  //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
+  DALI_TEST_EQUALS( true, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
+ */
+int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
+{
+  Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = MakeCheckerboardImageRGBA8888( 8, 8, 32 );
+  const unsigned int desiredWidth = 8;
+  const unsigned int desiredHeight = 8;
+
+  uint32_t outputImage[ desiredWidth * desiredHeight ];
+
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) &image->GetVector()[0], 256, 256, (unsigned char*) outputImage, desiredWidth, desiredHeight );
+
+  DALI_TEST_EQUALS( outputImage[0], 0xff0000ff, TEST_LOCATION ); // < Red corner pixel
+  DALI_TEST_EQUALS( outputImage[7], 0xff00ff00, TEST_LOCATION ); // < Green corner pixel
+  DALI_TEST_EQUALS( outputImage[8*8-1], 0xffff0000, TEST_LOCATION ); // < Blue corner pixel
+
+  DALI_TEST_EQUALS( outputImage[1], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[2], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[3], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[4], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[5], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[6], 0xffffffff, TEST_LOCATION ); // < white pixel
+
+  // Second scanline:
+  DALI_TEST_EQUALS( outputImage[8+0], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+1], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+2], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+3], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+4], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+5], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+6], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+7], 0xffffffff, TEST_LOCATION ); // < white pixel
+
+  // Third scanline:
+  DALI_TEST_EQUALS( outputImage[16+0], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+1], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+2], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+3], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+4], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+5], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+6], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+7], 0xff000000, TEST_LOCATION ); // < black pixel
+
+  // ... could do more scanlines (there are 8)
+
+  // Sample a few more pixels:
+
+  // Diagonals:
+  DALI_TEST_EQUALS( outputImage[24+3], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[32+4], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[40+5], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[48+6], 0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[24+4], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[32+3], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[40+2], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[48+1], 0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[56+0], 0xff000000, TEST_LOCATION ); // < black pixel
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that a scaling preserves input color in destination image.
+ */
+int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
+{
+  const unsigned int inputWidth = 137;
+  const unsigned int inputHeight = 571;
+  const unsigned int desiredWidth = 59;
+  const unsigned int desiredHeight = 257;
+
+  uint32_t inputImage[ inputWidth * inputHeight ];
+  MakeSingleColorImageRGBA8888( inputWidth, inputHeight, inputImage );
+
+  uint32_t *outputBuffer, *outputImage;
+  MakeGuardedOutputImageRGBA8888( desiredWidth, desiredHeight, outputBuffer, outputImage );
+
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, inputWidth, inputHeight, (unsigned char*) outputImage, desiredWidth, desiredHeight );
+
+  // Check that all the output pixels are the right color:
+  const uint32_t reference = inputImage[ inputWidth * inputHeight / 2];
+  unsigned int differentColorCount = 0;
+  for( unsigned int i = 0; i < desiredWidth * desiredHeight; ++i )
+  {
+    if( outputImage[i] != reference )
+    {
+      ++differentColorCount;
+    }
+  }
+
+  FreeReadOnlyPagesRGBA( outputBuffer, desiredWidth * desiredHeight );
+
+  DALI_TEST_EQUALS( 0U, differentColorCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that scaling down to a 1x1 image works.
+ */
+int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
+{
+  const unsigned int desiredWidth = 1;
+  const unsigned int desiredHeight = 1;
+
+  uint32_t inputImage[ 1024 * 1024 ];
+  MakeSingleColorImageRGBA8888( 1024, 1024, inputImage );
+  uint32_t outputImage = 0;
+
+  // Try several different starting image sizes:
+
+  // 1x1 -> 1x1:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Single-pixel wide tall stripe:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1, 1024, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Single-pixel tall, wide strip:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 1024,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Square mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  103,  103, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Wide mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  313,  79, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Tall mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   53,  467, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // 0 x 0 input image (make sure output not written to):
+  outputImage = 0xDEADBEEF;
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    0,    0, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, 0xDEADBEEF, TEST_LOCATION );
+  outputImage = 0;
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
+ * (edge-case)
+ */
+int UtcDaliImageOperationsPointSampleRGBA888ScaleToZeroDims(void)
+{
+  uint32_t inputImage[ 1024 * 1024 ];
+  MakeSingleColorImageRGBA8888( 1024, 1024, inputImage );
+  uint32_t* outputImage = AllocateReadOnlyPagesRGBA(1);
+
+  // Try several different starting image sizes:
+
+  // 1x1 -> 1x1:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1,    1, (unsigned char*) outputImage, 0, 0 );
+
+  // Single-pixel wide tall stripe:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1, 1024, (unsigned char*) outputImage, 0, 33 );
+
+  // Single-pixel tall, wide strip:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 1024,    1, (unsigned char*) outputImage, 0, 67 );
+
+  // Square mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  103,  103, (unsigned char*) outputImage, 21, 0 );
+
+  // Wide mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  313,  79, (unsigned char*) outputImage, 99, 0 );
+
+  // Tall mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   53,  467, (unsigned char*) outputImage, 9999, 0 );
+
+  // 0 x 0 input image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    0,    0, (unsigned char*) outputImage, 200, 99 );
+
+  FreeReadOnlyPagesRGBA( outputImage, getpagesize() / 4 );
+
+  //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
+  DALI_TEST_EQUALS( true, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that a scaling doesn't stray outside the bounds of the destination image.
+ *
+ * The test allocates a destination buffer that is an exact multiple of the page size
+ * with guard pages at either end.
+ */
+int UtcDaliImageOperationsPointSampleRGB88InBounds(void)
+{
+  const unsigned int inputWidth = 163;
+  const unsigned int inputHeight = 691;
+  const unsigned int desiredWidth = 32;
+  const unsigned int desiredHeight = 128;
+  const unsigned int outputBuffersizeInWords = desiredWidth * (desiredHeight / 4) * 3;
+
+  uint8_t inputImage[ inputWidth * inputHeight ][3];
+
+  // Allocate an output image buffer with read-only guard pages at either end:
+  // The test will segfault if it strays into the guard pages.
+  uint32_t *outputBuffer, *outputImage;
+
+  MakeGuardedOutputImageRGBA8888( desiredWidth * (desiredHeight / 4), 3, outputBuffer, outputImage );
+
+  Dali::Internal::Platform::PointSample3BPP( &inputImage[0][0], inputWidth, inputHeight, (uint8_t*) outputImage, desiredWidth, desiredHeight );
+
+  FreeReadOnlyPagesRGBA( outputBuffer, outputBuffersizeInWords );
+
+  //! The only real test is whether the above code SEGVs, but do a fake test so we pass if that hasn't happened:
+  DALI_TEST_EQUALS( true, true, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the small int (x,y) tuple.
+ */
+int UtcDaliImageOperationsUint16Pair(void)
+{
+  Uint16Pair vec1( 2, 3 );
+
+  DALI_TEST_EQUALS( vec1.GetWidth(), 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1.GetX(),     2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( vec1.GetHeight(), 3, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1.GetY(),      3, TEST_LOCATION );
+
+  Uint16Pair vec1Copy = vec1;
+
+  DALI_TEST_EQUALS( vec1Copy.GetWidth(), 2, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1Copy.GetX(),     2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( vec1Copy.GetHeight(), 3, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1Copy.GetY(),      3, TEST_LOCATION );
+
+  Uint16Pair vec2( 65535u, 65535u );
+
+  DALI_TEST_EQUALS( vec2.GetX(), 65535u, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec2.GetY(), 65535u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the four-tap linear blending for single-byte modes.
+ */
+int UtcDaliImageOperationsBilinearFilter1BPP(void)
+{
+  // Zeros blend to zero:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 32768, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 65535, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 65535 ), TEST_LOCATION );
+
+  // Ones and zeros average to 0.5:
+  DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 255, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 0, 255, 0, 255, 32768, 32768 ), TEST_LOCATION );
+
+  // Quarters ones average to 0.25:
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 255, 0, 0, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 255, 0, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 255, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
+
+  // Horizontal blends:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, 32768 ), TEST_LOCATION );
+  for( unsigned y = 0; y < 65536u; y += 256 )
+  {
+    // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
+    DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, y ), TEST_LOCATION );
+  }
+  DALI_TEST_EQUALS( 5u, BilinearFilter1Component( 0, 255, 0, 255, 1233, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 67u, BilinearFilter1Component( 0, 255, 0, 255, 17291, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 123u, BilinearFilter1Component( 0, 255, 0, 255, 31671, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 184u, BilinearFilter1Component( 0, 255, 0, 255, 47231, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 207u, BilinearFilter1Component( 0, 255, 0, 255, 53129, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 239u, BilinearFilter1Component( 0, 255, 0, 255, 61392, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 255, 0, 255, 65535, 32768 ), TEST_LOCATION );
+
+  // Vertical Blends:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 60u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 15379 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 130u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 33451 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 186u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 47836 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 244u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 62731 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 65535 ), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp
new file mode 100644 (file)
index 0000000..decd31a
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+#include <lifecycle-controller.h>
+
+#include <lifecycle-controller-impl.h>
+
+using namespace Dali;
+
+void utc_dali_lifecycle_controller_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_lifecycle_controller_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+bool g_OnInitCalled = false;
+bool g_OnTerminateCalled = false;
+bool g_OnPauseCalled = false;
+bool g_OnResumeCalled = false;
+bool g_OnResetCalled = false;
+bool g_OnResizeCalled = false;
+bool g_OnLanguageChangedCalled = false;
+
+void OnInit()
+{
+  g_OnInitCalled = true;
+}
+
+void OnTerminate()
+{
+  g_OnTerminateCalled = true;
+}
+
+void OnPause()
+{
+  g_OnPauseCalled = true;
+}
+
+void OnResume()
+{
+  g_OnResumeCalled = true;
+}
+
+void OnReset()
+{
+  g_OnResetCalled = true;
+}
+
+void OnResize()
+{
+  g_OnResizeCalled = true;
+}
+
+void OnLanguageChanged()
+{
+  g_OnLanguageChangedCalled = true;
+}
+
+} // anonymous namespace
+
+int UtcDaliLifecycleControllerGet(void)
+{
+  // Attempt to retrieve LifecycleController before creating application
+  LifecycleController lifecycleController;
+  lifecycleController = LifecycleController::Get();
+  DALI_TEST_CHECK( !lifecycleController );
+
+  Application application = Application::New();
+
+  lifecycleController = LifecycleController::Get();
+  DALI_TEST_CHECK( lifecycleController );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalInit(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnInitCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.InitSignal().Connect( &OnInit );
+
+  GetImplementation( lifecycleController ).OnInit( application );
+
+  DALI_TEST_CHECK( g_OnInitCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalTerminate(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnTerminateCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.TerminateSignal().Connect( &OnTerminate );
+
+  GetImplementation( lifecycleController ).OnTerminate( application );
+
+  DALI_TEST_CHECK( g_OnTerminateCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalPause(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnPauseCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.PauseSignal().Connect( &OnPause );
+
+  GetImplementation( lifecycleController ).OnPause( application );
+
+  DALI_TEST_CHECK( g_OnPauseCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalResume(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResumeCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResumeSignal().Connect( &OnResume );
+
+  GetImplementation( lifecycleController ).OnResume( application );
+
+  DALI_TEST_CHECK( g_OnResumeCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalReset(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResetCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResetSignal().Connect( &OnReset );
+
+  GetImplementation( lifecycleController ).OnReset( application );
+
+  DALI_TEST_CHECK( g_OnResetCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalResize(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResizeCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResizeSignal().Connect( &OnResize );
+
+  GetImplementation( lifecycleController ).OnResize( application );
+
+  DALI_TEST_CHECK( g_OnResizeCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalLanguageChanged(void)
+{
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnLanguageChangedCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.LanguageChangedSignal().Connect( &OnLanguageChanged );
+
+  GetImplementation( lifecycleController ).OnLanguageChanged( application );
+
+  DALI_TEST_CHECK( g_OnLanguageChangedCalled );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp
new file mode 100644 (file)
index 0000000..c3d6598
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <Ecore.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <tilt-sensor-impl.h>
+
+using namespace Dali;
+
+namespace
+{
+static const float ROTATION_EPSILON = 0.0001f;
+
+/**
+ * Helper to test whether timeout or tilt signal is received first
+ */
+struct SignalHelper : public ConnectionTracker
+{
+  SignalHelper()
+  : mTiltSignalReceived( false ),
+    mTimeoutOccurred( false )
+  {
+  }
+
+  void OnTilted(const TiltSensor& sensor)
+  {
+    tet_printf("tilted signal received\n");
+
+    mTiltSignalReceived = true;
+
+    // quit the main loop to continue test
+    //ecore_main_loop_quit();
+  }
+
+  bool OnTimeout()
+  {
+    tet_printf("timeout occurred\n");
+
+    mTimeoutOccurred = true;
+
+    // quit the main loop to continue test
+    //ecore_main_loop_quit();
+
+    return false;
+  }
+
+  bool mTiltSignalReceived; // True if tilted signal was received
+  bool mTimeoutOccurred;    // True if timeout occured
+};
+
+TiltSensor GetTiltSensor()
+{
+  return Internal::Adaptor::TiltSensor::New();
+}
+
+bool ecore_timer_running = false;
+Ecore_Task_Cb timer_callback_func=NULL;
+const void* timer_callback_data=NULL;
+intptr_t timerId = 8; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_timer_add below without compilation warnings
+}// anon namespace
+extern "C"
+{
+Ecore_Timer* ecore_timer_add(double in,
+                             Ecore_Task_Cb func,
+                             const void   *data)
+{
+  ecore_timer_running = true;
+  timer_callback_func = func;
+  timer_callback_data = data;
+  timerId+=8;
+  return (Ecore_Timer*)timerId;
+}
+
+void* ecore_timer_del(Ecore_Timer *timer)
+{
+  ecore_timer_running = false;
+  timer_callback_func = NULL;
+  return NULL;
+}
+
+}
+
+
+
+void tilt_sensor_startup(void)
+{
+}
+
+void tilt_sensor_cleanup(void)
+{
+}
+
+
+int UtcDaliTiltSensorEnable(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorEnable");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  sensor.Enable();
+  DALI_TEST_CHECK( sensor.IsEnabled() );
+
+  END_TEST;
+}
+
+int UtcDaliTiltSensorDisable(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorDisable");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  sensor.Enable();
+  DALI_TEST_CHECK( sensor.IsEnabled() );
+
+  sensor.Disable();
+  DALI_TEST_CHECK( !sensor.IsEnabled() );
+  END_TEST;
+}
+
+int UtcDaliTiltSensorIsEnabled(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorIsEnabled");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  // Should be disabled by default
+  DALI_TEST_CHECK( !sensor.IsEnabled() );
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetRoll(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetRoll");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  float roll = sensor.GetRoll();
+  DALI_TEST_CHECK( roll <= 1.0f && roll >= -1.0f ); // range check
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetPitch(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetPitch");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  float pitch = sensor.GetPitch();
+  DALI_TEST_CHECK( pitch <= 1.0f && pitch >= -1.0f ); // range check
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetRotation(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetRotation");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  Quaternion rotation = sensor.GetRotation();
+
+  Radian roll( sensor.GetRoll() );
+  Radian pitch( sensor.GetPitch() );
+
+  Quaternion expectedRotation = Quaternion( roll  * Math::PI * -0.5f, Vector3::YAXIS ) *
+                                Quaternion( pitch * Math::PI * -0.5f, Vector3::XAXIS );
+
+  DALI_TEST_EQUALS( rotation, expectedRotation, ROTATION_EPSILON, TEST_LOCATION );
+  END_TEST;
+}
+
+
+int UtcDaliTiltSensorSignalTilted(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSignalTilted");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.Enable();
+
+  Radian angle(Degree(-45));
+  //Setting a negative threshold for testing purpose
+  sensor.SetRotationThreshold( angle );
+
+  END_TEST;
+}
+
+int UtcDaliTiltSensorSetUpdateFrequency(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSetUpdateFrequency");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.SetUpdateFrequency( 1.0f/*hertz*/ );
+  DALI_TEST_EQUALS( sensor.GetUpdateFrequency(), 1.0f, TEST_LOCATION );
+
+  sensor.SetUpdateFrequency( 60.0f/*hertz*/ );
+  DALI_TEST_EQUALS( sensor.GetUpdateFrequency(), 60.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTiltSensorSetRotationThreshold01(void)
+{
+  TestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSetRotationThreshold01");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.Enable();
+
+  Radian angle(Degree(-45));
+  sensor.SetRotationThreshold( angle );
+  DALI_TEST_EQUALS( sensor.GetRotationThreshold(), angle, TEST_LOCATION );
+
+  angle = Degree(90);
+  sensor.SetRotationThreshold( angle );
+  DALI_TEST_EQUALS( sensor.GetRotationThreshold(), angle, TEST_LOCATION );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/CMakeLists.txt b/automated-tests/src/dali-adaptor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..788016a
--- /dev/null
@@ -0,0 +1,62 @@
+SET(PKG_NAME "dali-adaptor")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-adaptor")
+SET(TC_SOURCES
+    utc-Dali-Key.cpp
+    utc-Dali-NativeImageSource.cpp
+    utc-Dali-SingletonService.cpp
+    utc-Dali-Window.cpp
+    utc-Dali-Timer.cpp
+    utc-Dali-TtsPlayer.cpp
+    utc-Dali-Application.cpp
+)
+
+if(NOT UBUNTU_PROFILE)
+LIST(APPEND TC_SOURCES
+    utc-Dali-KeyGrab.cpp
+)
+endif()
+
+LIST(APPEND TC_SOURCES
+    dali-test-suite-utils/test-harness.cpp
+    dali-test-suite-utils/dali-test-suite-utils.cpp
+    dali-test-suite-utils/test-application.cpp
+    dali-test-suite-utils/test-gesture-manager.cpp
+    dali-test-suite-utils/test-gl-abstraction.cpp
+    dali-test-suite-utils/test-gl-sync-abstraction.cpp
+    dali-test-suite-utils/test-native-image.cpp
+    dali-test-suite-utils/test-platform-abstraction.cpp
+    dali-test-suite-utils/test-render-controller.cpp
+    dali-test-suite-utils/test-trace-call-stack.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali
+    ecore
+)
+
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror=return-type")
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${${CAPI_LIB}_CFLAGS_OTHER}")
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    dali-test-suite-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
new file mode 100644 (file)
index 0000000..f2cf564
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "dali-test-suite-utils.h"
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <cstdarg>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+
+using namespace Dali;
+
+int test_return_value = TET_UNDEF;
+
+void tet_result(int value)
+{
+  // First TET_PASS should set to zero
+  // first TET_FAIL should prevent any further TET_PASS from setting back to zero
+  // Any TET_FAIL should set to fail or leave as fail
+  if( test_return_value != 1 )
+    test_return_value = value;
+}
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+
+void tet_infoline(const char* str)
+{
+  fprintf(stderr, "%s\n", str);
+}
+
+void tet_printf(const char *format, ...)
+{
+  va_list arg;
+  va_start(arg, format);
+  vfprintf(stderr, format, arg);
+  va_end(arg);
+}
+
+/**
+ * DALI_TEST_CHECK is a wrapper for tet_result.
+ * If the condition evaluates to false, then the function & line number is printed.
+ * @param[in] The boolean expression to check
+ */
+#define DALI_TEST_CHECK(condition)                                                        \
+if ( (condition) )                                                                        \
+{                                                                                         \
+  tet_result(TET_PASS);                                                                   \
+}                                                                                         \
+else                                                                                      \
+{                                                                                         \
+  fprintf(stderr, "%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);    \
+  tet_result(TET_FAIL);                                                                   \
+}
+
+bool operator==(TimePeriod a, TimePeriod b)
+{
+  return Equals(a.durationSeconds, b.durationSeconds) && Equals(a.delaySeconds, b.delaySeconds) ;
+}
+
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value )
+{
+  return ostream << "( Duration:" << value.durationSeconds << " Delay:" << value.delaySeconds << ")";
+}
+
+std::ostream& operator<<( std::ostream& ostream, Radian angle )
+{
+  ostream << angle.radian;
+  return ostream;
+}
+
+std::ostream& operator<<( std::ostream& ostream, Degree angle )
+{
+  ostream << angle.degree;
+  return ostream;
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int i=0;i<9;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])< GetRangedEpsilon(m1[i], m2[i]));
+  }
+
+  if (!equivalent)
+  {
+    fprintf(stderr, "%s, checking\n"
+               "(%f, %f, %f)    (%f, %f, %f)\n"
+               "(%f, %f, %f) == (%f, %f, %f)\n"
+               "(%f, %f, %f)    (%f, %f, %f)\n",
+               location,
+               m1[0],  m1[1], m1[2],   m2[0],  m2[1], m2[2],
+               m1[3],  m1[4], m1[5],   m2[3],  m2[4], m2[5],
+               m1[6],  m1[7], m1[8],   m2[6],  m2[7], m2[8]);
+
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int i=0;i<9;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    fprintf(stderr, "%s, checking\n"
+               "(%f, %f, %f)    (%f, %f, %f)\n"
+               "(%f, %f, %f) == (%f, %f, %f)\n"
+               "(%f, %f, %f)    (%f, %f, %f)\n",
+               location,
+               m1[0],  m1[1], m1[2],   m2[0],  m2[1], m2[2],
+               m1[3],  m1[4], m1[5],   m2[3],  m2[4], m2[5],
+               m1[6],  m1[7], m1[8],   m2[6],  m2[7], m2[8]);
+
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool identical = true;
+
+  int i;
+  for (i=0;i<16;++i)
+  {
+    if(m1[i] != m2[i])
+    {
+      identical = false;
+      break;
+    }
+  }
+
+  if (!identical)
+  {
+    fprintf(stderr, "%s, checking\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n", location,
+               m1[0],  m1[1],  m1[2],  m1[3],   m2[0],  m2[1],  m2[2],  m2[3],
+               m1[4],  m1[5],  m1[6],  m1[7],   m2[4],  m2[5],  m2[6],  m2[7],
+               m1[8],  m1[9], m1[10], m1[11],   m2[8],  m2[9], m2[10], m2[11],
+              m1[12], m1[13], m1[14], m1[15],  m2[12], m2[13], m2[14], m2[15]);
+
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int i=0;i<16;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    fprintf(stderr, "%s, checking\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n"
+               "(%f, %f, %f, %f) == (%f, %f, %f, %f)\n", location,
+               m1[0],  m1[1],  m1[2],  m1[3],   m2[0],  m2[1],  m2[2],  m2[3],
+               m1[4],  m1[5],  m1[6],  m1[7],   m2[4],  m2[5],  m2[6],  m2[7],
+               m1[8],  m1[9], m1[10], m1[11],   m2[8],  m2[9], m2[10], m2[11],
+              m1[12], m1[13], m1[14], m1[15],  m2[12], m2[13], m2[14], m2[15]);
+
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2, location);
+}
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1, str2.c_str(), location);
+}
+
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location )
+{
+  if( NULL == strstr( e.condition, conditionSubString.c_str() ) )
+  {
+    fprintf(stderr, "Expected substring '%s' : actual exception string '%s' : location %s\n", conditionSubString.c_str(), e.condition, location );
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+// Functor to test whether an Applied signal is emitted
+ConstraintAppliedCheck::ConstraintAppliedCheck( bool& signalReceived )
+: mSignalReceived( signalReceived )
+{
+}
+
+void ConstraintAppliedCheck::operator()( Constraint& constraint )
+{
+  mSignalReceived = true;
+}
+
+void ConstraintAppliedCheck::Reset()
+{
+  mSignalReceived = false;
+}
+
+void ConstraintAppliedCheck::CheckSignalReceived()
+{
+  if ( !mSignalReceived )
+  {
+    fprintf(stderr,  "Expected Applied signal was not received\n" );
+    tet_result( TET_FAIL );
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+void ConstraintAppliedCheck::CheckSignalNotReceived()
+{
+  if ( mSignalReceived )
+  {
+    fprintf(stderr,  "Unexpected Applied signal was received\n" );
+    tet_result( TET_FAIL );
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+BufferImage CreateBufferImage()
+{
+  BufferImage image = BufferImage::New(4,4,Pixel::RGBA8888);
+
+  PixelBuffer* pixbuf = image.GetBuffer();
+
+  // Using a 4x4 image gives a better blend with the GL implementation
+  // than a 3x3 image
+  for(size_t i=0; i<16; i++)
+  {
+    pixbuf[i*4+0] = 0xFF;
+    pixbuf[i*4+1] = 0xFF;
+    pixbuf[i*4+2] = 0xFF;
+    pixbuf[i*4+3] = 0xFF;
+  }
+
+  return image;
+}
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h
new file mode 100644 (file)
index 0000000..8163028
--- /dev/null
@@ -0,0 +1,374 @@
+#ifndef __DALI_TEST_SUITE_UTILS_H__
+#define __DALI_TEST_SUITE_UTILS_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdarg>
+#include <iostream>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+
+void tet_infoline(const char*str);
+void tet_printf(const char *format, ...);
+
+#include "test-application.h"
+
+using namespace Dali;
+
+#define STRINGIZE_I(text) #text
+#define STRINGIZE(text) STRINGIZE_I(text)
+
+// the following is the other compilers way of token pasting, gcc seems to just concatenate strings automatically
+//#define TOKENPASTE(x,y) x ## y
+#define TOKENPASTE(x,y) x y
+#define TOKENPASTE2(x,y) TOKENPASTE( x, y )
+#define TEST_LOCATION TOKENPASTE2( "Test failed in ", TOKENPASTE2( __FILE__, TOKENPASTE2( ", line ", STRINGIZE(__LINE__) ) ) )
+
+#define TET_UNDEF 2
+#define TET_FAIL 1
+#define TET_PASS 0
+
+extern int test_return_value;
+
+void tet_result(int value);
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+void tet_infoline(const char* str);
+void tet_printf(const char *format, ...);
+
+/**
+ * DALI_TEST_CHECK is a wrapper for tet_result.
+ * If the condition evaluates to false, then the function & line number is printed.
+ * @param[in] The boolean expression to check
+ */
+#define DALI_TEST_CHECK(condition)                                                        \
+if ( (condition) )                                                                        \
+{                                                                                         \
+  tet_result(TET_PASS);                                                                   \
+}                                                                                         \
+else                                                                                      \
+{                                                                                         \
+  fprintf(stderr, "%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);    \
+  tet_result(TET_FAIL);                                                                   \
+}
+
+template <typename Type>
+inline bool CompareType(Type value1, Type value2, float epsilon);
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<float>(float value1, float value2, float epsilon)
+{
+  return fabsf(value1 - value2) < epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector2>(Vector2 vector1, Vector2 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon && fabsf(vector1.y - vector2.y)<epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector3 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector3>(Vector3 vector1, Vector3 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon;
+}
+
+
+/**
+ * A helper for fuzzy-comparing Vector4 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector4>(Vector4 vector1, Vector4 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon &&
+         fabsf(vector1.w - vector2.w)<epsilon;
+}
+
+template <>
+inline bool CompareType<Quaternion>(Quaternion q1, Quaternion q2, float epsilon)
+{
+  Quaternion q2N = -q2; // These quaternions represent the same rotation
+  return CompareType<Vector4>(q1.mVector, q2.mVector, epsilon) || CompareType<Vector4>(q1.mVector, q2N.mVector, epsilon);
+}
+
+template <>
+inline bool CompareType<Radian>(Radian q1, Radian q2, float epsilon)
+{
+  return CompareType<float>(q1.radian, q2.radian, epsilon);
+}
+
+template <>
+inline bool CompareType<Degree>(Degree q1, Degree q2, float epsilon)
+{
+  return CompareType<float>(q1.degree, q2.degree, epsilon);
+}
+
+bool operator==(TimePeriod a, TimePeriod b);
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value );
+std::ostream& operator<<( std::ostream& ostream, Radian angle );
+std::ostream& operator<<( std::ostream& ostream, Degree angle );
+
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<typename TypeA, typename TypeB>
+inline void DALI_TEST_EQUALS(TypeA value1, TypeB value2, const char* location)
+{
+  if (!(value1 == value2))
+  {
+    std::ostringstream o;
+    o << value1 << " == " << value2 << std::endl;
+    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+template<typename Type>
+inline void DALI_TEST_EQUALS(Type value1, Type value2, float epsilon, const char* location)
+{
+  if( !CompareType<Type>(value1, value2, epsilon) )
+  {
+    std::ostringstream o;
+    o << value1 << " == " << value2 << std::endl;
+    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two TimePeriods are within a certain distance of each other.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] epsilon The values must be within this distance of each other
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<TimePeriod>( TimePeriod value1, TimePeriod value2, float epsilon, const char* location)
+{
+  if ((fabs(value1.durationSeconds - value2.durationSeconds) > epsilon))
+  {
+    fprintf(stderr, "%s, checking durations %f == %f, epsilon %f\n", location, value1.durationSeconds, value2.durationSeconds, epsilon);
+    tet_result(TET_FAIL);
+  }
+  else if ((fabs(value1.delaySeconds - value2.delaySeconds) > epsilon))
+  {
+    fprintf(stderr, "%s, checking delays %f == %f, epsilon %f\n", location, value1.delaySeconds, value2.delaySeconds, epsilon);
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two Matrix3 objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location);
+
+/** Test whether two Matrix3 objects are equal (fuzzy compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] epsilon The epsilon to use for comparison
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal (fuzzy-compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<const char*>( const char* str1, const char* str2, const char* location)
+{
+  if (strcmp(str1, str2))
+  {
+    fprintf(stderr, "%s, checking '%s' == '%s'\n", location, str1, str2);
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<const std::string&>( const std::string &str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2.c_str(), location);
+}
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location);
+
+/**
+ * Test whether one unsigned integer value is greater than another.
+ * Test succeeds if value1 > value2
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template< typename T >
+void DALI_TEST_GREATER(unsigned int value1, unsigned int value2, const char* location)
+{
+  if (!(value1 > value2))
+  {
+    std::cerr << location << ", checking " << value1 <<" > " << value2 << "\n";
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether the assertion condition that failed and thus triggered the
+ * exception \b e contained a given substring.
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ * @param[in] conditionSubString The text that we expect to be present in an
+ *                               assertion which triggered the exception.
+ * @param[in] location The TEST_LOCATION macro should be used here.
+ */
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location );
+
+/**
+ * Print the assert
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ */
+inline void DALI_TEST_PRINT_ASSERT( DaliException& e )
+{
+  tet_printf("Assertion %s failed at %s\n", e.condition, e.location );
+}
+
+// Functor to test whether an Applied signal is emitted
+struct ConstraintAppliedCheck
+{
+  ConstraintAppliedCheck( bool& signalReceived );
+  void operator()( Constraint& constraint );
+  void Reset();
+  void CheckSignalReceived();
+  void CheckSignalNotReceived();
+  bool& mSignalReceived; // owned by individual tests
+};
+
+/**
+ * A Helper to test default functions
+ */
+template <typename T>
+struct DefaultFunctionCoverage
+{
+  DefaultFunctionCoverage()
+  {
+    T a;
+    T *b = new T(a);
+    DALI_TEST_CHECK(b);
+    a = *b;
+    delete b;
+  }
+};
+
+
+// Helper to Create bitmap image
+BufferImage CreateBufferImage();
+
+#endif // __DALI_TEST_SUITE_UTILS_H__
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp
new file mode 100644 (file)
index 0000000..89138eb
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-application.h"
+
+namespace Dali
+{
+
+
+TestApplication::TestApplication( size_t surfaceWidth,
+                                  size_t surfaceHeight,
+                                  float  horizontalDpi,
+                                  float  verticalDpi,
+                                  ResourcePolicy::DataRetention policy)
+: mCore( NULL ),
+  mSurfaceWidth( surfaceWidth ),
+  mSurfaceHeight( surfaceHeight ),
+  mFrame( 0u ),
+  mDpi( horizontalDpi, verticalDpi ),
+  mLastVSyncTime(0u),
+  mDataRetentionPolicy( policy )
+{
+  Initialize();
+}
+
+TestApplication::TestApplication( bool   initialize,
+                                  size_t surfaceWidth,
+                                  size_t surfaceHeight,
+                                  float  horizontalDpi,
+                                  float  verticalDpi,
+                                  ResourcePolicy::DataRetention policy)
+: mCore( NULL ),
+  mSurfaceWidth( surfaceWidth ),
+  mSurfaceHeight( surfaceHeight ),
+  mFrame( 0u ),
+  mDpi( horizontalDpi, verticalDpi ),
+  mDataRetentionPolicy( policy )
+{
+  if ( initialize )
+  {
+    Initialize();
+  }
+}
+
+void TestApplication::Initialize()
+{
+  mCore = Dali::Integration::Core::New(
+    mRenderController,
+    mPlatformAbstraction,
+    mGlAbstraction,
+    mGlSyncAbstraction,
+    mGestureManager,
+    mDataRetentionPolicy);
+
+  mCore->ContextCreated();
+  mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight );
+  mCore->SetDpi( mDpi.x, mDpi.y );
+
+  Dali::Integration::Log::LogFunction logFunction(&TestApplication::LogMessage);
+  Dali::Integration::Log::InstallLogFunction(logFunction);
+}
+
+TestApplication::~TestApplication()
+{
+  Dali::Integration::Log::UninstallLogFunction();
+  delete mCore;
+}
+
+void TestApplication::LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      fprintf(stderr, "INFO: %s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      fprintf(stderr, "WARN: %s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugError:
+      fprintf(stderr, "ERROR: %s", message.c_str());
+      break;
+    default:
+      fprintf(stderr, "DEFAULT: %s", message.c_str());
+      break;
+  }
+}
+
+Dali::Integration::Core& TestApplication::GetCore()
+{
+  return *mCore;
+}
+
+TestPlatformAbstraction& TestApplication::GetPlatform()
+{
+  return mPlatformAbstraction;
+}
+
+TestRenderController& TestApplication::GetRenderController()
+{
+  return mRenderController;
+}
+
+TestGlAbstraction& TestApplication::GetGlAbstraction()
+{
+  return mGlAbstraction;
+}
+
+TestGlSyncAbstraction& TestApplication::GetGlSyncAbstraction()
+{
+  return mGlSyncAbstraction;
+}
+
+TestGestureManager& TestApplication::GetGestureManager()
+{
+  return mGestureManager;
+}
+
+void TestApplication::ProcessEvent(const Integration::Event& event)
+{
+  mCore->QueueEvent(event);
+  mCore->ProcessEvents();
+}
+
+void TestApplication::SendNotification()
+{
+  mCore->ProcessEvents();
+}
+
+void TestApplication::SetSurfaceWidth( unsigned int width, unsigned height )
+{
+  mSurfaceWidth = width;
+  mSurfaceHeight = height;
+
+  mCore->SurfaceResized( mSurfaceWidth, mSurfaceHeight );
+}
+
+void TestApplication::DoUpdate( unsigned int intervalMilliseconds )
+{
+  unsigned int seconds(0u), microseconds(0u);
+  mPlatformAbstraction.GetTimeMicroseconds( seconds, microseconds );
+  mLastVSyncTime = ( seconds * 1e3 ) + ( microseconds / 1e3 );
+  unsigned int nextVSyncTime = mLastVSyncTime + 16;
+
+  // Update Time values
+  mPlatformAbstraction.IncrementGetTimeResult( intervalMilliseconds );
+
+  float elapsedSeconds = intervalMilliseconds / 1e3f;
+  mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus );
+}
+
+bool TestApplication::Render( unsigned int intervalMilliseconds  )
+{
+  DoUpdate( intervalMilliseconds );
+  mCore->Render( mRenderStatus );
+
+  mFrame++;
+
+  return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
+}
+
+unsigned int TestApplication::GetUpdateStatus()
+{
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::UpdateOnly( unsigned int intervalMilliseconds  )
+{
+  DoUpdate( intervalMilliseconds );
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::RenderOnly( )
+{
+  // Update Time values
+  mCore->Render( mRenderStatus );
+
+  mFrame++;
+
+  return mRenderStatus.NeedsUpdate();
+}
+
+void TestApplication::ResetContext()
+{
+  mCore->ContextDestroyed();
+  mCore->ContextCreated();
+}
+
+
+} // Namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h
new file mode 100644 (file)
index 0000000..c91086e
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef __DALI_TEST_APPLICATION_H__
+#define __DALI_TEST_APPLICATION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <test-platform-abstraction.h>
+#include "test-gesture-manager.h"
+#include "test-gl-sync-abstraction.h"
+#include "test-gl-abstraction.h"
+#include "test-render-controller.h"
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/resource-policies.h>
+
+namespace Dali
+{
+
+class DALI_IMPORT_API TestApplication : public ConnectionTracker
+{
+public:
+
+  // Default values derived from H2 device.
+  static const unsigned int DEFAULT_SURFACE_WIDTH = 480;
+  static const unsigned int DEFAULT_SURFACE_HEIGHT = 800;
+
+#ifdef _CPP11
+  static constexpr float DEFAULT_HORIZONTAL_DPI = 220.0f;
+  static constexpr float DEFAULT_VERTICAL_DPI   = 217.0f;
+#else
+  static const float DEFAULT_HORIZONTAL_DPI = 220.0f;
+  static const float DEFAULT_VERTICAL_DPI   = 217.0f;
+#endif
+
+  static const unsigned int DEFAULT_RENDER_INTERVAL = 1;
+
+  TestApplication( size_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                   size_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                   float  horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                   float  verticalDpi   = DEFAULT_VERTICAL_DPI,
+                   ResourcePolicy::DataRetention policy = ResourcePolicy::DALI_DISCARDS_ALL_DATA);
+
+  TestApplication( bool   initialize,
+                   size_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                   size_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                   float  horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                   float  verticalDpi   = DEFAULT_VERTICAL_DPI,
+                   ResourcePolicy::DataRetention policy = ResourcePolicy::DALI_DISCARDS_ALL_DATA);
+
+  void Initialize();
+  virtual ~TestApplication();
+  static void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message);
+  Dali::Integration::Core& GetCore();
+  TestPlatformAbstraction& GetPlatform();
+  TestRenderController& GetRenderController();
+  TestGlAbstraction& GetGlAbstraction();
+  TestGlSyncAbstraction& GetGlSyncAbstraction();
+  TestGestureManager& GetGestureManager();
+  void ProcessEvent(const Integration::Event& event);
+  void SendNotification();
+  void SetSurfaceWidth( unsigned int width, unsigned height );
+  bool Render( unsigned int intervalMilliseconds = DEFAULT_RENDER_INTERVAL );
+  unsigned int GetUpdateStatus();
+  bool UpdateOnly( unsigned int intervalMilliseconds = DEFAULT_RENDER_INTERVAL );
+  bool RenderOnly( );
+  void ResetContext();
+
+private:
+  void DoUpdate( unsigned int intervalMilliseconds );
+
+protected:
+  TestPlatformAbstraction   mPlatformAbstraction;
+  TestRenderController      mRenderController;
+  TestGlAbstraction         mGlAbstraction;
+  TestGlSyncAbstraction     mGlSyncAbstraction;
+  TestGestureManager        mGestureManager;
+
+  Integration::UpdateStatus mStatus;
+  Integration::RenderStatus mRenderStatus;
+
+  Integration::Core* mCore;
+
+  unsigned int mSurfaceWidth;
+  unsigned int mSurfaceHeight;
+  unsigned int mFrame;
+
+  Vector2 mDpi;
+  unsigned int mLastVSyncTime;
+  ResourcePolicy::DataRetention mDataRetentionPolicy;
+};
+
+} // Dali
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.cpp
new file mode 100644 (file)
index 0000000..2844ff1
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-gesture-manager.h"
+
+namespace Dali
+{
+
+TestGestureManager::TestGestureManager()
+{
+  Initialize();
+}
+
+/**
+ * Destructor
+ */
+TestGestureManager::~TestGestureManager()
+{
+}
+
+/**
+ * @copydoc Dali::Integration::GestureManager::Register(Gesture::Type)
+ */
+void TestGestureManager::Register(const Integration::GestureRequest& request)
+{
+  mFunctionsCalled.Register = true;
+}
+
+/**
+ * @copydoc Dali::Integration::GestureManager::Unregister(Gesture::Type)
+ */
+void TestGestureManager::Unregister(const Integration::GestureRequest& request)
+{
+  mFunctionsCalled.Unregister = true;
+}
+
+/**
+ * @copydoc Dali::Integration::GestureManager::Update(Gesture::Type)
+ */
+void TestGestureManager::Update(const Integration::GestureRequest& request)
+{
+  mFunctionsCalled.Update = true;
+}
+
+
+/** Call this every test */
+void TestGestureManager::Initialize()
+{
+  mFunctionsCalled.Reset();
+}
+
+bool TestGestureManager::WasCalled(TestFuncEnum func)
+{
+  switch(func)
+  {
+    case RegisterType:             return mFunctionsCalled.Register;
+    case UnregisterType:           return mFunctionsCalled.Unregister;
+    case UpdateType:               return mFunctionsCalled.Update;
+  }
+  return false;
+}
+
+void TestGestureManager::ResetCallStatistics(TestFuncEnum func)
+{
+  switch(func)
+  {
+    case RegisterType:             mFunctionsCalled.Register = false; break;
+    case UnregisterType:           mFunctionsCalled.Unregister = false; break;
+    case UpdateType:               mFunctionsCalled.Update = false; break;
+  }
+}
+
+TestGestureManager::TestFunctions::TestFunctions()
+: Register(false),
+  Unregister(false),
+  Update(false)
+{
+}
+
+void TestGestureManager::TestFunctions::Reset()
+{
+  Register = false;
+  Unregister = false;
+  Update = false;
+}
+
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-manager.h
new file mode 100644 (file)
index 0000000..4c0b766
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __DALI_TEST_GESTURE_MANAGER_H__
+#define __DALI_TEST_GESTURE_MANAGER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/gesture-manager.h>
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+/**
+ * Concrete implementation of the gesture manager class.
+ */
+class DALI_IMPORT_API TestGestureManager : public Dali::Integration::GestureManager
+{
+
+public:
+
+  /**
+   * Constructor
+   */
+  TestGestureManager();
+
+  /**
+   * Destructor
+   */
+  virtual ~TestGestureManager();
+
+  /**
+   * @copydoc Dali::Integration::GestureManager::Register(Gesture::Type)
+   */
+  virtual void Register(const Integration::GestureRequest& request);
+
+  /**
+   * @copydoc Dali::Integration::GestureManager::Unregister(Gesture::Type)
+   */
+  virtual void Unregister(const Integration::GestureRequest& request);
+
+  /**
+   * @copydoc Dali::Integration::GestureManager::Update(Gesture::Type)
+   */
+  virtual void Update(const Integration::GestureRequest& request);
+
+public: // TEST FUNCTIONS
+
+  // Enumeration of Gesture Manager methods
+  enum TestFuncEnum
+  {
+    RegisterType,
+    UnregisterType,
+    UpdateType,
+  };
+
+  /** Call this every test */
+  void Initialize();
+  bool WasCalled(TestFuncEnum func);
+  void ResetCallStatistics(TestFuncEnum func);
+
+private:
+
+  struct TestFunctions
+  {
+    TestFunctions();
+    void Reset();
+
+    bool Register;
+    bool Unregister;
+    bool Update;
+  };
+
+  TestFunctions mFunctionsCalled;
+};
+
+} // Dali
+
+#endif // __DALI_TEST_GESTURE_MANAGER_H__
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
new file mode 100644 (file)
index 0000000..d8af042
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-gl-abstraction.h"
+
+namespace Dali
+{
+
+TestGlAbstraction::TestGlAbstraction()
+{
+  Initialize();
+}
+
+TestGlAbstraction::~TestGlAbstraction() {}
+
+void TestGlAbstraction::Initialize()
+{
+  mCurrentProgram = 0;
+  mCompileStatus = GL_TRUE;
+  mLinkStatus = GL_TRUE;
+
+  mGetAttribLocationResult = 0;
+  mGetErrorResult = 0;
+  mGetStringResult = NULL;
+  mIsBufferResult = 0;
+  mIsEnabledResult = 0;
+  mIsFramebufferResult = 0;
+  mIsProgramResult = 0;
+  mIsRenderbufferResult = 0;
+  mIsShaderResult = 0;
+  mIsTextureResult = 0;
+  mVertexAttribArrayChanged = false;
+
+  mCheckFramebufferStatusResult = 0;
+  mFramebufferStatus = 0;
+  mFramebufferColorAttached = 0;
+  mFramebufferDepthAttached = 0;
+  mFramebufferStencilAttached = 0;
+
+  mNumBinaryFormats = 0;
+  mBinaryFormats = 0;
+  mProgramBinaryLength = 0;
+  mGetProgramBinaryCalled = false;
+
+  mLastAutoTextureIdUsed = 0;
+
+  mLastShaderIdUsed = 0;
+  mLastProgramIdUsed = 0;
+  mLastUniformIdUsed = 0;
+  mLastShaderCompiled = 0;
+  mLastClearBitMask = 0;
+  mClearCount = 0;
+
+  mLastBlendEquationRgb   = 0;
+  mLastBlendEquationAlpha = 0;
+  mLastBlendFuncSrcRgb    = 0;
+  mLastBlendFuncDstRgb    = 0;
+  mLastBlendFuncSrcAlpha  = 0;
+  mLastBlendFuncDstAlpha  = 0;
+
+  mUniforms.clear();
+  mProgramUniforms1i.clear();
+  mProgramUniforms1f.clear();
+  mProgramUniforms2f.clear();
+  mProgramUniforms3f.clear();
+  mProgramUniforms4f.clear();
+}
+
+void TestGlAbstraction::PreRender()
+{
+}
+
+void TestGlAbstraction::PostRender()
+{
+}
+
+} // Namespace dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams("Enable", out.str());
+  return blendEnabled;
+}
+
+bool BlendDisabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams("Disable", out.str());
+  return blendEnabled;
+}
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h
new file mode 100644 (file)
index 0000000..fa51412
--- /dev/null
@@ -0,0 +1,2001 @@
+#ifndef __TEST_GL_ABSTRACTION_H__
+#define __TEST_GL_ABSTRACTION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <string>
+#include <map>
+#include <cstdio>
+#include <cstring> // strcpy
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/gl-defines.h>
+
+// INTERNAL INCLUDES
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+static const unsigned int MAX_ATTRIBUTE_CACHE_SIZE = 64;
+static const char *mStdAttribs[MAX_ATTRIBUTE_CACHE_SIZE] =
+{
+    "aPosition",    // ATTRIB_POSITION
+    "aNormal",      // ATTRIB_NORMAL
+    "aTexCoord",    // ATTRIB_TEXCOORD
+    "aColor",       // ATTRIB_COLOR
+    "aBoneWeights", // ATTRIB_BONE_WEIGHTS
+    "aBoneIndices"  // ATTRIB_BONE_INDICES
+};
+
+class DALI_IMPORT_API TestGlAbstraction: public Dali::Integration::GlAbstraction
+{
+public:
+  TestGlAbstraction();
+  ~TestGlAbstraction();
+  void Initialize();
+
+  void PreRender();
+  void PostRender();
+
+  /* OpenGL ES 2.0 */
+
+  inline void ActiveTexture( GLenum textureUnit )
+  {
+    mActiveTextureUnit = textureUnit - GL_TEXTURE0;
+  }
+
+  inline GLenum GetActiveTextureUnit() const
+  {
+    return mActiveTextureUnit + GL_TEXTURE0;
+  }
+
+  inline void AttachShader( GLuint program, GLuint shader )
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+    mShaderTrace.PushCall("AttachShader", out.str());
+  }
+
+  inline void BindAttribLocation( GLuint program, GLuint index, const char* name )
+  {
+  }
+
+  inline void BindBuffer( GLenum target, GLuint buffer )
+  {
+  }
+
+  inline void BindFramebuffer( GLenum target, GLuint framebuffer )
+  {
+    //Add 010 bit;
+    mFramebufferStatus |= 2;
+  }
+
+  inline void BindRenderbuffer( GLenum target, GLuint renderbuffer )
+  {
+  }
+
+  /**
+   * This method can be used by test cases, to query the texture IDs that have been bound by BindTexture.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures() const
+  {
+    return mBoundTextures;
+  }
+
+  /**
+   * Query the texture IDs that have been bound with BindTexture, with a specific active texture unit.
+   * @param[in] activeTextureUnit The specific active texture unit.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures( GLuint activeTextureUnit ) const
+  {
+    return mActiveTextures[ activeTextureUnit - GL_TEXTURE0 ].mBoundTextures;
+  }
+
+  /**
+   * This method can be used by test cases, to clear the record of texture IDs that have been bound by BindTexture.
+   */
+  inline void ClearBoundTextures()
+  {
+    mBoundTextures.clear();
+
+    for( unsigned int i=0; i<MIN_TEXTURE_UNIT_LIMIT; ++i )
+    {
+      mActiveTextures[ i ].mBoundTextures.clear();
+    }
+  }
+
+  inline void BindTexture( GLenum target, GLuint texture )
+  {
+    // Record the bound textures for future checks
+    if( texture )
+    {
+      mBoundTextures.push_back( texture );
+
+      if( mActiveTextureUnit < MIN_TEXTURE_UNIT_LIMIT )
+      {
+        mActiveTextures[ mActiveTextureUnit ].mBoundTextures.push_back( texture );
+      }
+    }
+
+    std::stringstream out;
+    out << target << ", " << texture;
+    mTextureTrace.PushCall("BindTexture", out.str());
+  }
+
+  inline void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    mLastBlendColor.r = red;
+    mLastBlendColor.g = green;
+    mLastBlendColor.b = blue;
+    mLastBlendColor.a = alpha;
+  }
+
+  inline const Vector4& GetLastBlendColor() const
+  {
+    return mLastBlendColor;
+  }
+
+  inline void BlendEquation( GLenum mode )
+  {
+    mLastBlendEquationRgb   = mode;
+    mLastBlendEquationAlpha = mode;
+  }
+
+  inline void BlendEquationSeparate( GLenum modeRgb, GLenum modeAlpha )
+  {
+    mLastBlendEquationRgb   = modeRgb;
+    mLastBlendEquationAlpha = modeAlpha;
+  }
+
+  inline GLenum GetLastBlendEquationRgb() const
+  {
+    return mLastBlendEquationRgb;
+  }
+
+  inline GLenum GetLastBlendEquationAlpha() const
+  {
+    return mLastBlendEquationAlpha;
+  }
+
+  inline void BlendFunc(GLenum sfactor, GLenum dfactor)
+  {
+    mLastBlendFuncSrcRgb = sfactor;
+    mLastBlendFuncDstRgb = dfactor;
+    mLastBlendFuncSrcAlpha = sfactor;
+    mLastBlendFuncDstAlpha = dfactor;
+  }
+
+  inline void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+  {
+    mLastBlendFuncSrcRgb = srcRGB;
+    mLastBlendFuncDstRgb = dstRGB;
+    mLastBlendFuncSrcAlpha = srcAlpha;
+    mLastBlendFuncDstAlpha = dstAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncSrcRgb() const
+  {
+    return mLastBlendFuncSrcRgb;
+  }
+
+  inline GLenum GetLastBlendFuncDstRgb() const
+  {
+    return mLastBlendFuncDstRgb;
+  }
+
+  inline GLenum GetLastBlendFuncSrcAlpha() const
+  {
+    return mLastBlendFuncSrcAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncDstAlpha() const
+  {
+    return mLastBlendFuncDstAlpha;
+  }
+
+  inline void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+  {
+     mBufferDataCalls.push_back(size);
+  }
+
+  inline void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+  {
+     mBufferSubDataCalls.push_back(size);
+  }
+
+  inline GLenum CheckFramebufferStatus(GLenum target)
+  {
+    //If it has the three last bits set to 1 - 111, then the three minimum functions to create a
+    //Framebuffer texture have been called
+    if( mFramebufferStatus == 7 )
+    {
+      return GL_FRAMEBUFFER_COMPLETE;
+    }
+
+    return mCheckFramebufferStatusResult;
+  }
+
+  inline GLenum CheckFramebufferColorAttachment()
+  {
+    return mFramebufferColorAttached;
+  }
+
+  inline GLenum CheckFramebufferDepthAttachment()
+  {
+    return mFramebufferDepthAttached;
+  }
+
+  inline GLenum CheckFramebufferStencilAttachment()
+  {
+    return mFramebufferStencilAttached;
+  }
+
+  inline void Clear(GLbitfield mask)
+  {
+    mClearCount++;
+    mLastClearBitMask = mask;
+  }
+
+  inline void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+  }
+
+  inline void ClearDepthf(GLclampf depth)
+  {
+  }
+
+  inline void ClearStencil(GLint s)
+  {
+  }
+
+  inline void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+  {
+  }
+
+  inline void CompileShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+    mShaderTrace.PushCall("CompileShader", out.str());
+  }
+
+  inline void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+  {
+  }
+
+  inline void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+  {
+  }
+
+  inline void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+  {
+  }
+
+  inline void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline GLuint CreateProgram(void)
+  {
+    mShaderTrace.PushCall("CreateProgram", "");
+
+    ++mLastProgramIdUsed;
+    mUniforms[mLastProgramIdUsed] = UniformIDMap();
+    return mLastProgramIdUsed;
+  }
+
+  inline GLuint CreateShader(GLenum type)
+  {
+    std::stringstream out;
+    out << type;
+    mShaderTrace.PushCall("CreateShader", out.str());
+
+    return ++mLastShaderIdUsed;
+  }
+
+  inline void CullFace(GLenum mode)
+  {
+    std::stringstream out;
+    out << mode;
+    mCullFaceTrace.PushCall("CullFace", out.str());
+  }
+
+  inline void DeleteBuffers(GLsizei n, const GLuint* buffers)
+  {
+  }
+
+  inline void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+  {
+  }
+
+  inline void DeleteProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+    mShaderTrace.PushCall("DeleteProgram", out.str());
+  }
+
+  inline void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+  {
+  }
+
+  inline void DeleteShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+    mShaderTrace.PushCall("DeleteShader", out.str());
+  }
+
+  inline void DeleteTextures(GLsizei n, const GLuint* textures)
+  {
+    std::stringstream out;
+    out << n << ", " << textures << " = [" ;
+
+    for(GLsizei i=0; i<n; i++)
+    {
+      out << textures[i] << ", " ;
+      mDeletedTextureIds.push_back(textures[i]);
+    }
+    out << "]";
+    mTextureTrace.PushCall("DeleteTextures", out.str());
+  }
+
+  inline bool CheckNoTexturesDeleted()
+  {
+    return mDeletedTextureIds.size() == 0;
+  }
+
+  inline bool CheckTextureDeleted( GLuint textureId )
+  {
+    bool found = false;
+
+    for(std::vector<GLuint>::iterator iter=mDeletedTextureIds.begin(); iter != mDeletedTextureIds.end(); ++iter)
+    {
+      if(*iter == textureId)
+      {
+        found = true;
+        break;
+      }
+    }
+    return found;
+  }
+
+  inline void ClearDeletedTextures()
+  {
+    mDeletedTextureIds.clear();
+  }
+
+  inline void DepthFunc(GLenum func)
+  {
+  }
+
+  inline void DepthMask(GLboolean flag)
+  {
+  }
+
+  inline void DepthRangef(GLclampf zNear, GLclampf zFar)
+  {
+  }
+
+  inline void DetachShader(GLuint program, GLuint shader)
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+    mShaderTrace.PushCall("DetachShader", out.str());
+  }
+
+  inline void Disable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    mCullFaceTrace.PushCall("Disable", out.str());
+  }
+
+  inline void DisableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, false );
+  }
+
+  inline void DrawArrays(GLenum mode, GLint first, GLsizei count)
+  {
+    std::stringstream out;
+    out << mode << ", " << first << ", " << count;
+    mDrawTrace.PushCall("DrawArrays", out.str());
+  }
+
+  inline void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
+  {
+    std::stringstream out;
+    out << mode << ", " << count << ", " << type << ", indices";
+    mDrawTrace.PushCall("DrawElements", out.str());
+  }
+
+  inline void Enable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    mCullFaceTrace.PushCall("Enable", out.str());
+  }
+
+  inline void EnableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, true);
+  }
+
+  inline void Finish(void)
+  {
+  }
+
+  inline void Flush(void)
+  {
+  }
+
+  inline void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+  {
+    if (attachment == GL_DEPTH_ATTACHMENT)
+    {
+      mFramebufferDepthAttached = true;
+    }
+    else if (attachment == GL_STENCIL_ATTACHMENT)
+    {
+      mFramebufferStencilAttached = true;
+    }
+  }
+
+  inline void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+  {
+    //Add 100 bit;
+    mFramebufferStatus |= 4;
+
+    //We check 4 attachment colors
+    if ((attachment == GL_COLOR_ATTACHMENT0) || (attachment == GL_COLOR_ATTACHMENT1) || (attachment == GL_COLOR_ATTACHMENT2)  || (attachment == GL_COLOR_ATTACHMENT4))
+    {
+      mFramebufferColorAttached = true;
+    }
+  }
+
+  inline void FrontFace(GLenum mode)
+  {
+  }
+
+  inline void GenBuffers(GLsizei n, GLuint* buffers)
+  {
+    // avoids an assert in GpuBuffers
+    *buffers = 1u;
+  }
+
+  inline void GenerateMipmap(GLenum target)
+  {
+  }
+
+  inline void GenFramebuffers(GLsizei n, GLuint* framebuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      framebuffers[i] = i + 1;
+    }
+
+    //Add 001 bit, this function needs to be called the first one in the chain
+    mFramebufferStatus = 1;
+  }
+
+  inline void GenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      renderbuffers[i] = i + 1;
+    }
+  }
+
+  /**
+   * This method can be used by test cases, to manipulate the texture IDs generated by GenTextures.
+   * @param[in] ids A vector containing the next IDs to be generated
+   */
+  inline void SetNextTextureIds( const std::vector<GLuint>& ids )
+  {
+    mNextTextureIds = ids;
+  }
+
+  inline const std::vector<GLuint>& GetNextTextureIds()
+  {
+    return mNextTextureIds;
+  }
+
+  inline void GenTextures(GLsizei n, GLuint* textures)
+  {
+    for( int i=0; i<n; ++i )
+    {
+      if( !mNextTextureIds.empty() )
+      {
+        *(textures+i) = mNextTextureIds[0];
+        mNextTextureIds.erase( mNextTextureIds.begin() );
+      }
+      else
+      {
+        *(textures+i) = ++mLastAutoTextureIdUsed;
+      }
+    }
+
+    std::stringstream out;
+    for(int i=0; i<n; i++)
+    {
+      out << textures[i];
+      if(i<n-1)
+      {
+        out << ", ";
+      }
+    }
+    mTextureTrace.PushCall("GenTextures", out.str());
+  }
+
+  inline void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+  }
+
+  inline void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+  }
+
+  inline void GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+  {
+  }
+
+  inline int  GetAttribLocation(GLuint program, const char* name)
+  {
+    std::string attribName(name);
+
+    for( unsigned int i = 0; i < ATTRIB_TYPE_LAST; ++i )
+    {
+      if( mStdAttribs[i] == attribName )
+      {
+        return i;
+      }
+    }
+
+    // 0 is a valid location
+    return 0;
+  }
+
+  inline void GetBooleanv(GLenum pname, GLboolean* params)
+  {
+  }
+
+  inline void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLenum GetError(void)
+  {
+    return mGetErrorResult;
+  }
+
+  inline void GetFloatv(GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetIntegerv(GLenum pname, GLint* params)
+  {
+    switch( pname )
+    {
+      case GL_MAX_TEXTURE_SIZE:
+        *params = 2048;
+        break;
+      case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *params = 8;
+        break;
+      case GL_NUM_PROGRAM_BINARY_FORMATS_OES:
+        *params = mNumBinaryFormats;
+        break;
+      case GL_PROGRAM_BINARY_FORMATS_OES:
+        *params = mBinaryFormats;
+        break;
+    }
+  }
+
+  inline void GetProgramiv(GLuint program, GLenum pname, GLint* params)
+  {
+    switch( pname ) {
+      case GL_LINK_STATUS:
+        *params = mLinkStatus;
+        break;
+      case GL_PROGRAM_BINARY_LENGTH_OES:
+        *params = mProgramBinaryLength;
+        break;
+    }
+  }
+
+  inline void GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+
+  inline void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetShaderiv(GLuint shader, GLenum pname, GLint* params)
+  {
+    switch( pname ) {
+      case GL_COMPILE_STATUS:
+        *params = mCompileStatus;
+        break;
+    }
+  }
+
+  inline void GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+  inline void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+  {
+  }
+
+  inline const GLubyte* GetString(GLenum name)
+  {
+    return mGetStringResult;
+  }
+
+  inline void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetUniformfv(GLuint program, GLint location, GLfloat* params)
+  {
+  }
+
+  inline void GetUniformiv(GLuint program, GLint location, GLint* params)
+  {
+  }
+
+  inline GLint GetUniformLocation(GLuint program, const char* name)
+  {
+    ProgramUniformMap::iterator it = mUniforms.find(program);
+    if( it == mUniforms.end() )
+    {
+      // Not a valid program ID
+      mGetErrorResult = GL_INVALID_OPERATION;
+      return -1;
+    }
+
+    UniformIDMap& uniformIDs = it->second;
+    UniformIDMap::iterator it2 = uniformIDs.find( name );
+    if( it2 == uniformIDs.end() )
+    {
+      // Uniform not found, so add it...
+      uniformIDs[name] = ++mLastUniformIdUsed;
+      return mLastUniformIdUsed;
+    }
+
+    return it2->second;
+  }
+
+  inline void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+  {
+  }
+
+  inline void Hint(GLenum target, GLenum mode)
+  {
+  }
+
+  inline GLboolean IsBuffer(GLuint buffer)
+  {
+    return mIsBufferResult;
+  }
+
+  inline GLboolean IsEnabled(GLenum cap)
+  {
+    return mIsEnabledResult;
+  }
+
+  inline GLboolean IsFramebuffer(GLuint framebuffer)
+  {
+    return mIsFramebufferResult;
+  }
+
+  inline GLboolean IsProgram(GLuint program)
+  {
+    return mIsProgramResult;
+  }
+
+  inline GLboolean IsRenderbuffer(GLuint renderbuffer)
+  {
+    return mIsRenderbufferResult;
+  }
+
+  inline GLboolean IsShader(GLuint shader)
+  {
+    return mIsShaderResult;
+  }
+
+  inline GLboolean IsTexture(GLuint texture)
+  {
+    return mIsTextureResult;
+  }
+
+  inline void LineWidth(GLfloat width)
+  {
+  }
+
+  inline void LinkProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+    mShaderTrace.PushCall("LinkProgram", out.str());
+  }
+
+  inline void PixelStorei(GLenum pname, GLint param)
+  {
+  }
+
+  inline void PolygonOffset(GLfloat factor, GLfloat units)
+  {
+  }
+
+  inline void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+  {
+  }
+
+  inline void ReleaseShaderCompiler(void)
+  {
+  }
+
+  inline void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void SampleCoverage(GLclampf value, GLboolean invert)
+  {
+  }
+
+  inline void Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    mScissorParams.x = x;
+    mScissorParams.y = y;
+    mScissorParams.width = width;
+    mScissorParams.height = height;
+  }
+
+  inline void ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+  {
+  }
+
+  inline void ShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+  {
+    std::string stringBuilder;
+    for(int i = 0; i < count; ++i)
+    {
+      stringBuilder += string[i];
+    }
+    mShaderSources[shader] = stringBuilder;
+    mLastShaderCompiled = shader;
+  }
+
+  inline void GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+  {
+    const std::string shaderSource = mShaderSources[shader];
+    if( static_cast<int>(shaderSource.length()) < bufsize )
+    {
+      strcpy(source, shaderSource.c_str());
+      *length = shaderSource.length();
+    }
+    else
+    {
+      *length = bufsize -1;
+      strncpy(source, shaderSource.c_str(), *length);
+      source[*length] = 0x0;
+    }
+  }
+
+  inline std::string GetShaderSource(GLuint shader)
+  {
+    return mShaderSources[shader];
+  }
+
+  inline void StencilFunc(GLenum func, GLint ref, GLuint mask)
+  {
+  }
+
+  inline void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+  {
+  }
+
+  inline void StencilMask(GLuint mask)
+  {
+  }
+
+  inline void StencilMaskSeparate(GLenum face, GLuint mask)
+  {
+  }
+
+  inline void StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+  {
+  }
+
+  inline void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+  {
+  }
+
+  inline void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << width << ", " << height;
+    mTextureTrace.PushCall("TexImage2D", out.str());
+  }
+
+  inline void TexParameterf(GLenum target, GLenum pname, GLfloat param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+    mTexParamaterTrace.PushCall("TexParameterf", out.str());
+  }
+
+  inline void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+    mTexParamaterTrace.PushCall("TexParameterfv", out.str());
+  }
+
+  inline void TexParameteri(GLenum target, GLenum pname, GLint param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+    mTexParamaterTrace.PushCall("TexParameteri", out.str());
+  }
+
+  inline void TexParameteriv(GLenum target, GLenum pname, const GLint* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+    mTexParamaterTrace.PushCall("TexParameteriv", out.str());
+  }
+
+  inline void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << xoffset << ", " << yoffset << ", " << width << ", " << height;
+    mTextureTrace.PushCall("TexSubImage2D", out.str());
+  }
+
+  inline void Uniform1f(GLint location, GLfloat x)
+  {
+    if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, x ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform1i(GLint location, GLint x)
+  {
+    if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram, location, x ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1iv(GLint location, GLsizei count, const GLint* v)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2f(GLint location, GLfloat x, GLfloat y)
+  {
+    if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector2( x, y ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform2fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 Vector2( v[2*i], v[2*i+1] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2i(GLint location, GLint x, GLint y)
+  {
+  }
+
+  inline void Uniform2iv(GLint location, GLsizei count, const GLint* v)
+  {
+  }
+
+  inline void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+  {
+    if( ! mProgramUniforms3f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector3( x, y, z ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform3fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms3f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector3( v[3*i], v[3*i+1], v[3*i+2] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform3i(GLint location, GLint x, GLint y, GLint z)
+  {
+  }
+
+  inline void Uniform3iv(GLint location, GLsizei count, const GLint* v)
+  {
+  }
+
+  inline void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+    if( ! mProgramUniforms4f.SetUniformValue( mCurrentProgram,
+                                              location,
+                                              Vector4( x, y, z, w ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform4fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms4f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector4( v[4*i], v[4*i+1], v[4*i+2], v[4*i+3] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+  {
+  }
+
+  inline void Uniform4iv(GLint location, GLsizei count, const GLint* v)
+  {
+  }
+
+  inline void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat3.SetUniformValue(
+            mCurrentProgram,
+            location,
+            Matrix3( value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat4.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Matrix( value ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UseProgram(GLuint program)
+  {
+    mCurrentProgram = program;
+  }
+
+  inline void ValidateProgram(GLuint program)
+  {
+  }
+
+  inline void VertexAttrib1f(GLuint indx, GLfloat x)
+  {
+  }
+
+  inline void VertexAttrib1fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+  {
+  }
+
+  inline void VertexAttrib2fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+  {
+  }
+
+  inline void VertexAttrib3fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+  }
+
+  inline void VertexAttrib4fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+  {
+  }
+
+  inline void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  /* OpenGL ES 3.0 */
+
+  inline void ReadBuffer(GLenum mode)
+  {
+  }
+
+  inline void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices)
+  {
+  }
+
+  inline void TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void GenQueries(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline void DeleteQueries(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsQuery(GLuint id)
+  {
+    return false;
+  }
+
+  inline void BeginQuery(GLenum target, GLuint id)
+  {
+  }
+
+  inline void EndQuery(GLenum target)
+  {
+  }
+
+  inline void GetQueryiv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline GLboolean UnmapBuffer(GLenum target)
+  {
+    return false;
+  }
+
+  inline void GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params)
+  {
+  }
+
+  inline void DrawBuffers(GLsizei n, const GLenum* bufs)
+  {
+  }
+
+  inline void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+  {
+  }
+
+  inline void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+  {
+  }
+
+  inline GLvoid* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+  {
+    return NULL;
+  }
+
+  inline void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+  {
+  }
+
+  inline void BindVertexArray(GLuint array)
+  {
+  }
+
+  inline void DeleteVertexArrays(GLsizei n, const GLuint* arrays)
+  {
+  }
+
+  inline void GenVertexArrays(GLsizei n, GLuint* arrays)
+  {
+  }
+
+  inline GLboolean IsVertexArray(GLuint array)
+  {
+    return false;
+  }
+
+  inline void GetIntegeri_v(GLenum target, GLuint index, GLint* data)
+  {
+  }
+
+  inline void BeginTransformFeedback(GLenum primitiveMode)
+  {
+  }
+
+  inline void EndTransformFeedback(void)
+  {
+  }
+
+  inline void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+  {
+  }
+
+  inline void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
+  {
+  }
+
+  inline void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode)
+  {
+  }
+
+  inline void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name)
+  {
+  }
+
+  inline void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+  {
+  }
+
+  inline void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
+  {
+  }
+
+  inline void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+  {
+  }
+
+  inline void VertexAttribI4iv(GLuint index, const GLint* v)
+  {
+  }
+
+  inline void VertexAttribI4uiv(GLuint index, const GLuint* v)
+  {
+  }
+
+  inline void GetUniformuiv(GLuint program, GLint location, GLuint* params)
+  {
+  }
+
+  inline GLint GetFragDataLocation(GLuint program, const GLchar *name)
+  {
+    return -1;
+  }
+
+  inline void Uniform1ui(GLint location, GLuint v0)
+  {
+  }
+
+  inline void Uniform2ui(GLint location, GLuint v0, GLuint v1)
+  {
+  }
+
+  inline void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+  {
+  }
+
+  inline void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+  {
+  }
+
+  inline void Uniform1uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform2uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform3uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform4uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value)
+  {
+  }
+
+  inline void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value)
+  {
+  }
+
+  inline void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+  {
+  }
+
+  inline const GLubyte* GetStringi(GLenum name, GLuint index)
+  {
+    return NULL;
+  }
+
+  inline void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+  {
+  }
+
+  inline void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices)
+  {
+  }
+
+  inline void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName)
+  {
+    return GL_INVALID_INDEX;
+  }
+
+  inline void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName)
+  {
+  }
+
+  inline void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+  {
+  }
+
+  inline void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+  {
+  }
+
+  inline void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount)
+  {
+  }
+
+  inline GLsync FenceSync(GLenum condition, GLbitfield flags)
+  {
+    return NULL;
+  }
+
+  inline GLboolean IsSync(GLsync sync)
+  {
+    return false;
+  }
+
+  inline void DeleteSync(GLsync sync)
+  {
+  }
+
+  inline GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+    return 0;
+  }
+
+  inline void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+  }
+
+  inline void GetInteger64v(GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values)
+  {
+  }
+
+  inline void GetInteger64i_v(GLenum target, GLuint index, GLint64* data)
+  {
+  }
+
+  inline void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GenSamplers(GLsizei count, GLuint* samplers)
+  {
+  }
+
+  inline void DeleteSamplers(GLsizei count, const GLuint* samplers)
+  {
+  }
+
+  inline GLboolean IsSampler(GLuint sampler)
+  {
+    return false;
+  }
+
+  inline void BindSampler(GLuint unit, GLuint sampler)
+  {
+  }
+
+  inline void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
+  {
+  }
+
+  inline void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param)
+  {
+  }
+
+  inline void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
+  {
+  }
+
+  inline void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param)
+  {
+  }
+
+  inline void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void VertexAttribDivisor(GLuint index, GLuint divisor)
+  {
+  }
+
+  inline void BindTransformFeedback(GLenum target, GLuint id)
+  {
+  }
+
+  inline void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline void GenTransformFeedbacks(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsTransformFeedback(GLuint id)
+  {
+    return false;
+  }
+
+  inline void PauseTransformFeedback(void)
+  {
+  }
+
+  inline void ResumeTransformFeedback(void)
+  {
+  }
+
+  inline void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)
+  {
+    mGetProgramBinaryCalled = true;
+  }
+
+  inline void ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length)
+  {
+  }
+
+  inline void ProgramParameteri(GLuint program, GLenum pname, GLint value)
+  {
+  }
+
+  inline void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
+  {
+  }
+
+  inline void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+  {
+  }
+
+  inline void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
+  {
+  }
+
+public: // TEST FUNCTIONS
+  inline void SetCompileStatus( GLuint value ) { mCompileStatus = value; }
+  inline void SetLinkStatus( GLuint value ) { mLinkStatus = value; }
+  inline void SetGetAttribLocationResult(  int result) { mGetAttribLocationResult = result; }
+  inline void SetGetErrorResult(  GLenum result) { mGetErrorResult = result; }
+  inline void SetGetStringResult(  GLubyte* result) { mGetStringResult = result; }
+  inline void SetIsBufferResult(  GLboolean result) { mIsBufferResult = result; }
+  inline void SetIsEnabledResult(  GLboolean result) { mIsEnabledResult = result; }
+  inline void SetIsFramebufferResult(  GLboolean result) { mIsFramebufferResult = result; }
+  inline void SetIsProgramResult(  GLboolean result) { mIsProgramResult = result; }
+  inline void SetIsRenderbufferResult(  GLboolean result) { mIsRenderbufferResult = result; }
+  inline void SetIsShaderResult(  GLboolean result) { mIsShaderResult = result; }
+  inline void SetIsTextureResult(  GLboolean result) { mIsTextureResult = result; }
+  inline void SetCheckFramebufferStatusResult(  GLenum result) { mCheckFramebufferStatusResult = result; }
+  inline void SetNumBinaryFormats( GLint numFormats ) { mNumBinaryFormats = numFormats; }
+  inline void SetBinaryFormats( GLint binaryFormats ) { mBinaryFormats = binaryFormats; }
+  inline void SetProgramBinaryLength( GLint length ) { mProgramBinaryLength = length; }
+
+  inline bool GetVertexAttribArrayState(GLuint index)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return false;
+    }
+    return mVertexAttribArrayState[ index ];
+  }
+  inline void ClearVertexAttribArrayChanged() {  mVertexAttribArrayChanged = false; }
+  inline bool GetVertexAttribArrayChanged()  { return mVertexAttribArrayChanged; }
+
+  //Methods for CullFace verification
+  inline void EnableCullFaceCallTrace(bool enable) { mCullFaceTrace.Enable(enable); }
+  inline void ResetCullFaceCallStack() { mCullFaceTrace.Reset(); }
+  inline TraceCallStack& GetCullFaceTrace() { return mCullFaceTrace; }
+
+  //Methods for Shader verification
+  inline void EnableShaderCallTrace(bool enable) { mShaderTrace.Enable(enable); }
+  inline void ResetShaderCallStack() { mShaderTrace.Reset(); }
+  inline TraceCallStack& GetShaderTrace() { return mShaderTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTextureCallTrace(bool enable) { mTextureTrace.Enable(enable); }
+  inline void ResetTextureCallStack() { mTextureTrace.Reset(); }
+  inline TraceCallStack& GetTextureTrace() { return mTextureTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTexParameterCallTrace(bool enable) { mTexParamaterTrace.Enable(enable); }
+  inline void ResetTexParameterCallStack() { mTexParamaterTrace.Reset(); }
+  inline TraceCallStack& GetTexParameterTrace() { return mTexParamaterTrace; }
+
+  //Methods for Draw verification
+  inline void EnableDrawCallTrace(bool enable) { mDrawTrace.Enable(enable); }
+  inline void ResetDrawCallStack() { mDrawTrace.Reset(); }
+  inline TraceCallStack& GetDrawTrace() { return mDrawTrace; }
+
+  template <typename T>
+  inline bool GetUniformValue( const char* name, T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        return mProgramUniforms.GetUniformValue( programId, uniformId, value );
+      }
+    }
+    return false;
+  }
+
+
+  template <typename T>
+  inline bool CheckUniformValue( const char* name, const T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        if( mProgramUniforms.CheckUniformValue( programId, uniformId, value ) )
+        {
+          // the value matches
+          return true;
+        }
+      }
+    }
+
+    fprintf(stderr, "Not found, printing possible values:\n" );
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        T origValue;
+        if ( mProgramUniforms.GetUniformValue(programId, uniformId, origValue) )
+        {
+          std::stringstream out;
+          out << uniform_it->first << ": " << origValue;
+          fprintf(stderr, "%s\n", out.str().c_str() );
+        }
+      }
+    }
+    return false;
+  }
+
+  template <typename T>
+  inline bool GetUniformValue( GLuint programId, GLuint uniformId, T& outValue) const
+  {
+    const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( outValue );
+    return mProgramUniforms.GetUniformValue( programId, uniformId, outValue );
+  }
+
+  inline bool GetUniformIds( const char* name, GLuint& programId, GLuint& uniformId ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        programId = program_it->first;
+        uniformId = uniform_it->second;
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  inline GLuint GetLastShaderCompiled() const
+  {
+    return mLastShaderCompiled;
+  }
+
+  inline GLuint GetLastProgramCreated() const
+  {
+    return mLastProgramIdUsed;
+  }
+
+  inline GLbitfield GetLastClearMask() const
+  {
+    return mLastClearBitMask;
+  }
+
+  enum AttribType
+  {
+    ATTRIB_UNKNOWN = -1,
+    ATTRIB_POSITION,
+    ATTRIB_NORMAL,
+    ATTRIB_TEXCOORD,
+    ATTRIB_COLOR,
+    ATTRIB_BONE_WEIGHTS,
+    ATTRIB_BONE_INDICES,
+    ATTRIB_TYPE_LAST
+  };
+
+  struct ScissorParams
+  {
+    GLint x;
+    GLint y;
+    GLsizei width;
+    GLsizei height;
+
+    ScissorParams() : x( 0 ), y( 0 ), width( 0 ), height( 0 ) { }
+  };
+
+  // Methods to check scissor tests
+  inline const ScissorParams& GetScissorParams() const { return mScissorParams; }
+
+  inline bool GetProgramBinaryCalled() const { return mGetProgramBinaryCalled; }
+
+  inline unsigned int GetClearCountCalled() const { return mClearCount; }
+
+  typedef std::vector<size_t> BufferDataCalls;
+  inline const BufferDataCalls& GetBufferDataCalls() const { return mBufferDataCalls; }
+  inline void ResetBufferDataCalls() { mBufferDataCalls.clear(); }
+
+  typedef std::vector<size_t> BufferSubDataCalls;
+  inline const BufferSubDataCalls& GetBufferSubDataCalls() const { return mBufferSubDataCalls; }
+  inline void ResetBufferSubDataCalls() { mBufferSubDataCalls.clear(); }
+
+private:
+  GLuint     mCurrentProgram;
+  GLuint     mCompileStatus;
+  BufferDataCalls mBufferDataCalls;
+  BufferSubDataCalls mBufferSubDataCalls;
+  GLuint     mLinkStatus;
+  GLint      mGetAttribLocationResult;
+  GLenum     mGetErrorResult;
+  GLubyte*   mGetStringResult;
+  GLboolean  mIsBufferResult;
+  GLboolean  mIsEnabledResult;
+  GLboolean  mIsFramebufferResult;
+  GLboolean  mIsProgramResult;
+  GLboolean  mIsRenderbufferResult;
+  GLboolean  mIsShaderResult;
+  GLboolean  mIsTextureResult;
+  GLenum     mActiveTextureUnit;
+  GLenum     mCheckFramebufferStatusResult;
+  GLint      mFramebufferStatus;
+  GLenum     mFramebufferColorAttached;
+  GLenum     mFramebufferDepthAttached;
+  GLenum     mFramebufferStencilAttached;
+  GLint      mNumBinaryFormats;
+  GLint      mBinaryFormats;
+  GLint      mProgramBinaryLength;
+  bool       mVertexAttribArrayState[MAX_ATTRIBUTE_CACHE_SIZE];
+  bool       mVertexAttribArrayChanged;                            // whether the vertex attrib array has been changed
+  bool       mGetProgramBinaryCalled;
+  typedef std::map< GLuint, std::string> ShaderSourceMap;
+  ShaderSourceMap mShaderSources;
+  GLuint     mLastShaderCompiled;
+  GLbitfield mLastClearBitMask;
+  unsigned int mClearCount;
+
+  Vector4 mLastBlendColor;
+  GLenum  mLastBlendEquationRgb;
+  GLenum  mLastBlendEquationAlpha;
+  GLenum  mLastBlendFuncSrcRgb;
+  GLenum  mLastBlendFuncDstRgb;
+  GLenum  mLastBlendFuncSrcAlpha;
+  GLenum  mLastBlendFuncDstAlpha;
+
+  // Data for manipulating the IDs returned by GenTextures
+  GLuint mLastAutoTextureIdUsed;
+  std::vector<GLuint> mNextTextureIds;
+  std::vector<GLuint> mDeletedTextureIds;
+  std::vector<GLuint> mBoundTextures;
+
+  struct ActiveTextureType
+  {
+    std::vector<GLuint> mBoundTextures;
+  };
+
+  ActiveTextureType mActiveTextures[ MIN_TEXTURE_UNIT_LIMIT ];
+
+  TraceCallStack mCullFaceTrace;
+  TraceCallStack mShaderTrace;
+  TraceCallStack mTextureTrace;
+  TraceCallStack mTexParamaterTrace;
+  TraceCallStack mDrawTrace;
+
+  // Shaders & Uniforms
+  GLuint mLastShaderIdUsed;
+  GLuint mLastProgramIdUsed;
+  GLuint mLastUniformIdUsed;
+  typedef std::map< std::string, GLint > UniformIDMap;
+  typedef std::map< GLuint, UniformIDMap > ProgramUniformMap;
+  ProgramUniformMap mUniforms;
+
+  template <typename T>
+  struct ProgramUniformValue : public std::map< GLuint, std::map< GLint, T > >
+  {
+  public:
+    typedef std::map< GLint, T > UniformValueMap;
+    typedef std::map< GLuint, UniformValueMap > Map;
+
+    bool SetUniformValue( GLuint program, GLuint uniform, const T& value )
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // if its the first uniform for this program add it
+        std::pair< typename Map::iterator, bool > result =
+            Map::insert( typename Map::value_type( program, UniformValueMap() ) );
+        it = result.first;
+      }
+
+      UniformValueMap& uniforms = it->second;
+      uniforms[uniform] = value;
+
+      return true;
+    }
+
+    bool CheckUniformValue( GLuint program, GLuint uniform, const T& value ) const
+    {
+      T uniformValue;
+      if ( GetUniformValue( program, uniform, uniformValue ) )
+      {
+        return value == uniformValue;
+      }
+
+      return false;
+    }
+
+    bool GetUniformValue( GLuint program, GLuint uniform, T& value ) const
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::const_iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+
+      const UniformValueMap& uniforms = it->second;
+      typename UniformValueMap::const_iterator it2 = uniforms.find( uniform );
+      if( it2 == uniforms.end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+      value = it2->second;
+
+      return true;
+    }
+
+    T GetZero() const;
+  };
+  ProgramUniformValue<int> mProgramUniforms1i;
+  ProgramUniformValue<float> mProgramUniforms1f;
+  ProgramUniformValue<Vector2> mProgramUniforms2f;
+  ProgramUniformValue<Vector3> mProgramUniforms3f;
+  ProgramUniformValue<Vector4> mProgramUniforms4f;
+  ProgramUniformValue<Matrix> mProgramUniformsMat4;
+  ProgramUniformValue<Matrix3> mProgramUniformsMat3;
+
+  inline const ProgramUniformValue<int>& GetProgramUniformsForType( const int ) const
+  {
+    return mProgramUniforms1i;
+  }
+  inline const ProgramUniformValue<float>& GetProgramUniformsForType( const float ) const
+  {
+    return mProgramUniforms1f;
+  }
+  inline const ProgramUniformValue<Vector2>& GetProgramUniformsForType( const Vector2& ) const
+  {
+    return mProgramUniforms2f;
+  }
+  inline const ProgramUniformValue<Vector3>& GetProgramUniformsForType( const Vector3& ) const
+  {
+    return mProgramUniforms3f;
+  }
+  inline const ProgramUniformValue<Vector4>& GetProgramUniformsForType( const Vector4& ) const
+  {
+    return mProgramUniforms4f;
+  }
+  inline const ProgramUniformValue<Matrix>& GetProgramUniformsForType( const Matrix& ) const
+  {
+    return mProgramUniformsMat4;
+  }
+  inline const ProgramUniformValue<Matrix3>& GetProgramUniformsForType( const Matrix3& ) const
+  {
+    return mProgramUniformsMat3;
+  }
+  inline void SetVertexAttribArray(GLuint index, bool state)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return;
+    }
+    mVertexAttribArrayState[ index ] = state;
+    mVertexAttribArrayChanged = true;
+  }
+
+  ScissorParams mScissorParams;
+};
+
+template <>
+inline int TestGlAbstraction::ProgramUniformValue<int>::GetZero() const
+{
+  return 0;
+}
+
+template <>
+inline float TestGlAbstraction::ProgramUniformValue<float>::GetZero() const
+{
+  return 0.0f;
+}
+
+template <>
+inline Vector2 TestGlAbstraction::ProgramUniformValue<Vector2>::GetZero() const
+{
+  return Vector2::ZERO;
+}
+
+template <>
+inline Vector3 TestGlAbstraction::ProgramUniformValue<Vector3>::GetZero() const
+{
+  return Vector3::ZERO;
+}
+
+template <>
+inline Vector4 TestGlAbstraction::ProgramUniformValue<Vector4>::GetZero() const
+{
+  return Vector4::ZERO;
+}
+
+template <>
+inline Matrix TestGlAbstraction::ProgramUniformValue<Matrix>::GetZero() const
+{
+  return Matrix();
+}
+
+template <>
+inline Matrix3 TestGlAbstraction::ProgramUniformValue<Matrix3>::GetZero() const
+{
+  return Matrix3( Matrix() );
+}
+
+} // namespace Dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack);
+bool BlendDisabled(const Dali::TraceCallStack& callStack);
+
+
+
+
+#endif // __TEST_GL_ES_H__
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp
new file mode 100644 (file)
index 0000000..533355c
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-gl-sync-abstraction.h"
+
+namespace Dali
+{
+
+TestSyncObject::TestSyncObject(TraceCallStack& trace)
+: synced(false),
+  mTrace(trace)
+{
+}
+
+TestSyncObject::~TestSyncObject()
+{
+}
+
+bool TestSyncObject::IsSynced()
+{
+  mTrace.PushCall("SyncObject::IsSynced", ""); // Trace the method
+  return synced;
+}
+
+
+
+TestGlSyncAbstraction::TestGlSyncAbstraction()
+{
+  Initialize();
+}
+
+/**
+ * Destructor
+ */
+TestGlSyncAbstraction::~TestGlSyncAbstraction()
+{
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    delete *iter;
+  }
+}
+
+/**
+ * Initialize the sync objects - clear down the map
+ */
+void TestGlSyncAbstraction::Initialize()
+{
+  mSyncObjects.clear();
+}
+
+/**
+ * Create a sync object
+ * @return the sync object
+ */
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObject( )
+{
+  mTrace.PushCall("CreateSyncObject", ""); // Trace the method
+
+  TestSyncObject* syncObject = new TestSyncObject(mTrace);
+  mSyncObjects.push_back( syncObject );
+  return syncObject;
+}
+
+/**
+ * Destroy a sync object
+ * @param[in] syncObject The object to destroy
+ */
+void TestGlSyncAbstraction::DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject )
+{
+  std::stringstream out;
+  out << syncObject;
+  mTrace.PushCall("DestroySyncObject", out.str()); // Trace the method
+
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    if( *iter == syncObject )
+    {
+      delete *iter;
+      mSyncObjects.erase(iter);
+      break;
+    }
+  }
+}
+
+
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncObject( )
+{
+  if( !mSyncObjects.empty() )
+  {
+    return mSyncObjects.back();
+  }
+  return NULL;
+}
+
+/**
+ * Test method to trigger the object sync behaviour.
+ * @param[in]
+ * @param[in] sync The sync value to set
+ */
+void TestGlSyncAbstraction::SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync )
+{
+  TestSyncObject* testSyncObject = static_cast<TestSyncObject*>(syncObject);
+  testSyncObject->synced = sync;
+}
+
+/**
+ * Turn trace on
+ */
+void TestGlSyncAbstraction::EnableTrace(bool enable) { mTrace.Enable(enable); }
+
+/**
+ * Reset the trace callstack
+ */
+void TestGlSyncAbstraction::ResetTrace() { mTrace.Reset(); }
+
+/**
+ * Get the trace object (allows test case to find methods on it)
+ */
+TraceCallStack& TestGlSyncAbstraction::GetTrace() { return mTrace; }
+
+
+} // Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h
new file mode 100644 (file)
index 0000000..e233176
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef __TEST_GL_SYNC_ABSTRACTION_H__
+#define __TEST_GL_SYNC_ABSTRACTION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <string>
+#include <map>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-sync-abstraction.h>
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+class DALI_IMPORT_API TestSyncObject : public Integration::GlSyncAbstraction::SyncObject
+{
+public:
+  TestSyncObject(TraceCallStack& trace);
+  ~TestSyncObject();
+  bool IsSynced();
+  bool synced;
+  TraceCallStack& mTrace;
+};
+
+/**
+ * Class to emulate the GL sync functions with tracing
+ */
+class DALI_IMPORT_API TestGlSyncAbstraction: public Integration::GlSyncAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  TestGlSyncAbstraction();
+
+  /**
+   * Destructor
+   */
+  ~TestGlSyncAbstraction();
+
+  /**
+   * Initialize the sync objects - clear down the map
+   */
+  void Initialize();
+
+  /**
+   * Create a sync object
+   * @return the sync object
+   */
+  virtual Integration::GlSyncAbstraction::SyncObject* CreateSyncObject( );
+
+  /**
+   * Destroy a sync object
+   * @param[in] syncObject The object to destroy
+   */
+  virtual void DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject );
+
+
+public: // TEST FUNCTIONS
+  Integration::GlSyncAbstraction::SyncObject* GetLastSyncObject( );
+
+  /**
+   * Test method to trigger the object sync behaviour.
+   * @param[in]
+   * @param[in] sync The sync value to set
+   */
+  void SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync );
+
+  /**
+   * Turn trace on
+   */
+  void EnableTrace(bool enable);
+
+  /**
+   * Reset the trace callstack
+   */
+  void ResetTrace();
+
+  /**
+   * Get the trace object (allows test case to find methods on it)
+   */
+  TraceCallStack& GetTrace();
+
+private:
+  typedef std::vector<TestSyncObject*>   SyncContainer;
+  typedef SyncContainer::iterator SyncIter;
+  SyncContainer mSyncObjects;  ///< The sync objects
+  TraceCallStack mTrace; ///< the trace call stack for testing
+};
+
+} // Dali
+
+#endif // __TEST_GL_SYNC_ABSTRACTION_H__
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp
new file mode 100644 (file)
index 0000000..55beebc
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test-harness.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <testcase.h>
+
+namespace TestHarness
+{
+
+typedef std::map<int, TestCase> RunningTestCases;
+
+namespace
+{
+const char* RED_COLOR="\e[1;31m";
+const char* GREEN_COLOR="\e[1;32m";
+const char* ASCII_RESET="\e[0m";
+const char* ASCII_BOLD="\e[1m";
+}
+
+
+int RunTestCase( struct ::testcase_s& testCase )
+{
+  int result = EXIT_STATUS_TESTCASE_FAILED;
+
+// dont want to catch exception as we want to be able to get
+// gdb stack trace from the first error
+// by default tests should all always pass with no exceptions
+  if( testCase.startup )
+  {
+    testCase.startup();
+  }
+  result = testCase.function();
+  if( testCase.cleanup )
+  {
+    testCase.cleanup();
+  }
+
+  return result;
+}
+
+
+int RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
+{
+  int testResult = EXIT_STATUS_TESTCASE_FAILED;
+
+  int pid = fork();
+  if( pid == 0 ) // Child process
+  {
+    if( suppressOutput )
+    {
+      close(STDOUT_FILENO);
+      close(STDERR_FILENO);
+    }
+    exit( RunTestCase( testCase ) );
+  }
+  else if(pid == -1)
+  {
+    perror("fork");
+    exit(EXIT_STATUS_FORK_FAILED);
+  }
+  else // Parent process
+  {
+    int status = 0;
+    int childPid = waitpid(-1, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", testCase.name, testResult);
+        }
+      }
+    }
+    else if(WIFSIGNALED(status) )
+    {
+      testResult = EXIT_STATUS_TESTCASE_ABORTED;
+
+#ifdef WCOREDUMP
+      if(WCOREDUMP(status))
+      {
+        printf("Test case %s failed: due to a crash\n", testCase.name);
+      }
+#endif
+      printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
+    }
+    else if(WIFSTOPPED(status))
+    {
+      printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
+    }
+  }
+  return testResult;
+}
+
+void OutputStatistics( int numPasses, int numFailures )
+{
+  const char* failureColor = GREEN_COLOR;
+  if( numFailures > 0 )
+  {
+    failureColor = RED_COLOR;
+  }
+  printf("\rNumber of test passes:   %s%4d (%5.2f%%)%s\n", ASCII_BOLD, numPasses, 100.0f * (float)numPasses / (numPasses+numFailures),  ASCII_RESET);
+  printf("%sNumber of test failures:%s %s%4d%s\n", failureColor, ASCII_RESET, ASCII_BOLD, numFailures, ASCII_RESET);
+
+}
+
+
+int RunAll(const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+  int numFailures = 0;
+  int numPasses = 0;
+
+  // Run test cases in child process( to kill output/handle signals ), but run serially.
+  for( unsigned int i=0; tc_array[i].name; i++)
+  {
+    int result = RunTestCaseInChildProcess( tc_array[i], true );
+    if( result == 0 )
+    {
+      numPasses++;
+    }
+    else
+    {
+      numFailures++;
+    }
+  }
+
+  OutputStatistics(numPasses, numFailures);
+
+  return numFailures;
+}
+
+
+
+// Constantly runs up to MAX_NUM_CHILDREN processes
+int RunAllInParallel(  const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+  int numFailures = 0;
+  int numPasses = 0;
+
+  RunningTestCases children;
+  std::vector<int> failedTestCases;
+
+  // Fork up to MAX_NUM_CHILDREN processes, then
+  // wait. As soon as a proc completes, fork the next.
+
+  int nextTestCase = 0;
+  int numRunningChildren = 0;
+
+  while( tc_array[nextTestCase].name || numRunningChildren > 0)
+  {
+    // Create more children (up to the max number or til the end of the array)
+    while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
+    {
+      int pid = fork();
+      if( pid == 0 ) // Child process
+      {
+        close(STDOUT_FILENO);
+        close(STDERR_FILENO);
+        exit( RunTestCase( tc_array[nextTestCase] ) );
+      }
+      else if(pid == -1)
+      {
+        perror("fork");
+        exit(EXIT_STATUS_FORK_FAILED);
+      }
+      else // Parent process
+      {
+        TestCase tc(nextTestCase, tc_array[nextTestCase].name);
+        children[pid] = tc;
+        nextTestCase++;
+        numRunningChildren++;
+      }
+    }
+
+    // Wait for the next child to finish
+
+    int status=0;
+    int childPid = waitpid(-1, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        int testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
+          failedTestCases.push_back(children[childPid].testCase);
+          numFailures++;
+        }
+        else
+        {
+          numPasses++;
+        }
+        numRunningChildren--;
+      }
+    }
+
+    else if( WIFSIGNALED(status) || WIFSTOPPED(status))
+    {
+      status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
+
+      if( childPid > 0 )
+      {
+        RunningTestCases::iterator iter = children.find(childPid);
+        if( iter != children.end() )
+        {
+          printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
+          failedTestCases.push_back(iter->second.testCase);
+        }
+        else
+        {
+          printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
+        }
+
+        numFailures++;
+        numRunningChildren--;
+      }
+    }
+  }
+
+  OutputStatistics( numPasses, numFailures );
+
+  if( reRunFailed )
+  {
+    for( unsigned int i=0; i<failedTestCases.size(); i++)
+    {
+      char* testCaseStrapline;
+      int numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
+      printf("\n%s\n", testCaseStrapline);
+      for(int j=0; j<numChars; j++)
+      {
+        printf("=");
+      }
+      printf("\n");
+      RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
+    }
+  }
+
+  return numFailures;
+}
+
+
+
+int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
+{
+  int result = EXIT_STATUS_TESTCASE_NOT_FOUND;
+
+  for( int i = 0; tc_array[i].name; i++ )
+  {
+    if( !strcmp(testCaseName, tc_array[i].name) )
+    {
+      return RunTestCase( tc_array[i] );
+    }
+  }
+
+  printf("Unknown testcase name: \"%s\"\n", testCaseName);
+  return result;
+}
+
+void Usage(const char* program)
+{
+  printf("Usage: \n"
+         "   %s <testcase name>\t\t Execute a test case\n"
+         "   %s \t\t Execute all test cases in parallel\n"
+         "   %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n",
+         program, program, program);
+}
+
+} // namespace
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h
new file mode 100644 (file)
index 0000000..e6dc517
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef TEST_HARNESS_H
+#define TEST_HARNESS_H
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <testcase.h>
+
+namespace TestHarness
+{
+
+enum ExitStatus
+{
+  EXIT_STATUS_TESTCASE_SUCCEEDED,   // 0
+  EXIT_STATUS_TESTCASE_FAILED,      // 1
+  EXIT_STATUS_TESTCASE_ABORTED,     // 2
+  EXIT_STATUS_FORK_FAILED,          // 3
+  EXIT_STATUS_WAITPID_FAILED,       // 4
+  EXIT_STATUS_BAD_ARGUMENT,         // 5
+  EXIT_STATUS_TESTCASE_NOT_FOUND    // 6
+};
+
+const int MAX_NUM_CHILDREN(16);
+
+struct TestCase
+{
+  int testCase;
+  const char* testCaseName;
+
+  TestCase()
+  : testCase(0),
+    testCaseName(NULL)
+  {
+  }
+
+  TestCase(int tc, const char* name)
+  : testCase(tc),
+    testCaseName(name)
+  {
+  }
+  TestCase(const TestCase& rhs)
+  : testCase(rhs.testCase),
+    testCaseName(rhs.testCaseName)
+  {
+  }
+  TestCase& operator=(const TestCase& rhs)
+  {
+    testCase = rhs.testCase;
+    testCaseName = rhs.testCaseName;
+    return *this;
+
+  }
+};
+
+/**
+ * Run a test case
+ * @param[in] testCase The Testkit-lite test case to run
+ */
+int RunTestCase( struct testcase_s& testCase );
+
+/**
+ * Run all test cases in parallel
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int RunAllInParallel(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Run all test cases in serial
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int RunAll(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Find the named test case in the given array, and run it
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] testCaseName the name of the test case to run
+ * @return 0 on success
+ */
+int FindAndRunTestCase(::testcase tc_array[], const char* testCaseName);
+
+/**
+ * Display usage instructions for this program
+ * @param[in] program The name of this program
+ */
+void Usage(const char* program);
+
+} // namespace TestHarness
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp
new file mode 100644 (file)
index 0000000..b15dfbc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "test-application.h"
+#include "test-native-image.h"
+
+
+namespace Dali
+{
+
+TestNativeImagePointer TestNativeImage::New(int width, int height)
+{
+  return new TestNativeImage(width, height);
+}
+
+TestNativeImage::TestNativeImage(int width, int height)
+: mWidth(width), mHeight(height)
+{
+}
+
+TestNativeImage::~TestNativeImage()
+{
+}
+
+} // namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h
new file mode 100644 (file)
index 0000000..720b429
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef __TEST_NATIVE_IMAGE_H__
+#define __TEST_NATIVE_IMAGE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/images/native-image-interface.h>
+
+namespace Dali
+{
+class TestNativeImage;
+typedef IntrusivePtr<TestNativeImage> TestNativeImagePointer;
+
+class DALI_IMPORT_API TestNativeImage : public Dali::NativeImageInterface
+{
+public:
+  static TestNativeImagePointer New(int width, int height);
+
+  inline virtual bool GlExtensionCreate() {return true;};
+  inline virtual void GlExtensionDestroy() {};
+  inline virtual GLenum TargetTexture() {return 1;};
+  inline virtual void PrepareTexture() {};
+  inline virtual unsigned int GetWidth() const {return mWidth;};
+  inline virtual unsigned int GetHeight() const {return mHeight;};
+  inline virtual bool RequiresBlending() const {return true;};
+
+private:
+  TestNativeImage(int width, int height);
+  virtual ~TestNativeImage();
+
+  int mWidth;
+  int mHeight;
+};
+
+} // Dali
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
new file mode 100644 (file)
index 0000000..d9ea25e
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-platform-abstraction.h"
+#include "dali-test-suite-utils.h"
+#include <dali/integration-api/bitmap.h>
+
+namespace Dali
+{
+
+/**
+ * Constructor
+ */
+TestPlatformAbstraction::TestPlatformAbstraction()
+: mRequest(0)
+{
+  Initialize();
+}
+
+/**
+ * Destructor
+ */
+TestPlatformAbstraction::~TestPlatformAbstraction()
+{
+}
+
+/**
+ * @copydoc PlatformAbstraction::GetTimeMicroseconds()
+ */
+void TestPlatformAbstraction::GetTimeMicroseconds(unsigned int &seconds, unsigned int &microSeconds)
+{
+  seconds = mSeconds;
+  microSeconds = mMicroSeconds;
+  mTrace.PushCall("GetTimeMicroseconds", "");
+}
+
+/**
+ * @copydoc PlatformAbstraction::Suspend()
+ */
+void TestPlatformAbstraction::Suspend()
+{
+  mTrace.PushCall("Suspend", "");
+}
+
+/**
+ * @copydoc PlatformAbstraction::Resume()
+ */
+void TestPlatformAbstraction::Resume()
+{
+  mTrace.PushCall("Resume", "");
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( const std::string& filename,
+                                                              ImageDimensions size,
+                                                              FittingMode::Type fittingMode,
+                                                              SamplingMode::Type samplingMode,
+                                                              bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize.x, mClosestSize.y );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                                   ImageDimensions size,
+                                                   FittingMode::Type fittingMode,
+                                                   SamplingMode::Type samplingMode,
+                                                   bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize.x, mClosestSize.y );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+/**
+ * @copydoc PlatformAbstraction::LoadResource()
+ */
+void TestPlatformAbstraction::LoadResource(const Integration::ResourceRequest& request)
+{
+  std::ostringstream out;
+  out << "Type:" << request.GetType()->id << ", Path: " << request.GetPath() << std::endl ;
+
+  mTrace.PushCall("LoadResource", out.str());
+  if(mRequest != NULL)
+  {
+    delete mRequest;
+    tet_infoline ("Warning: multiple resource requests not handled by Test Suite. You may see unexpected errors");
+  }
+  mRequest = new Integration::ResourceRequest(request);
+}
+
+Integration::ResourcePointer TestPlatformAbstraction::LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath )
+{
+  mTrace.PushCall("LoadResourceSynchronously", "");
+  return mResources.loadedResource;
+}
+
+Integration::BitmapPtr TestPlatformAbstraction::DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t size )
+{
+  mTrace.PushCall("DecodeBuffer", "");
+  return Integration::BitmapPtr();
+}
+
+/**
+ * @copydoc PlatformAbstraction::CancelLoad()
+ */
+void TestPlatformAbstraction::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
+{
+  mTrace.PushCall("CancelLoad", "");
+}
+
+/**
+ * @copydoc PlatformAbstraction::GetResources()
+ */
+void TestPlatformAbstraction::GetResources(Integration::ResourceCache& cache)
+{
+  mTrace.PushCall("GetResources", "");
+
+  if(mResources.loaded)
+  {
+    cache.LoadResponse( mResources.loadedId, mResources.loadedType, mResources.loadedResource, Integration::RESOURCE_COMPLETELY_LOADED );
+  }
+  if(mResources.loadFailed)
+  {
+    cache.LoadFailed( mResources.loadFailedId, mResources.loadFailure );
+  }
+}
+
+/**
+ * @copydoc PlatformAbstraction::IsLoading()
+ */
+bool TestPlatformAbstraction::IsLoading()
+{
+  mTrace.PushCall("IsLoading", "");
+  return mIsLoadingResult;
+}
+
+/**
+ * @copydoc PlatformAbstraction::GetDefaultFontSize()
+ */
+int TestPlatformAbstraction::GetDefaultFontSize() const
+{
+  // TODO
+  return int();
+}
+
+/**
+ * @copydoc PlatformAbstraction::SetDpi()
+ */
+void TestPlatformAbstraction::SetDpi (unsigned int dpiHorizontal, unsigned int dpiVertical)
+{
+  mTrace.PushCall("SetDpi", "");
+}
+
+/**
+ * @copydoc PlatformAbstraction::LoadFile()
+ */
+bool TestPlatformAbstraction::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  mTrace.PushCall("LoadFile", "");
+  if( mLoadFileResult.loadResult )
+  {
+    buffer = mLoadFileResult.buffer;
+  }
+
+  return mLoadFileResult.loadResult;
+}
+
+/**
+ * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
+ */
+bool TestPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  mTrace.PushCall("LoadShaderBinaryFile", "");
+  if( mLoadFileResult.loadResult )
+  {
+    buffer = mLoadFileResult.buffer;
+  }
+
+  return mLoadFileResult.loadResult;
+}
+
+/**
+ * @copydoc PlatformAbstraction::SaveFile()
+ */
+bool TestPlatformAbstraction::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes) const
+{
+  mTrace.PushCall("SaveFile", "");
+  return false;
+}
+
+void TestPlatformAbstraction::JoinLoaderThreads()
+{
+  mTrace.PushCall("JoinLoaderThreads", "");
+}
+
+/** Call this every test */
+void TestPlatformAbstraction::Initialize()
+{
+  mTrace.Reset();
+  mTrace.Enable(true);
+  memset(&mResources, 0, sizeof(Resources));
+  mSeconds=0;
+  mMicroSeconds=0;
+  mIsLoadingResult=false;
+
+  if(mRequest)
+  {
+    delete mRequest;
+    mRequest = 0;
+  }
+}
+
+
+bool TestPlatformAbstraction::WasCalled(TestFuncEnum func)
+{
+  switch(func)
+  {
+    case GetTimeMicrosecondsFunc:             return mTrace.FindMethod("GetTimeMicroseconds");
+    case SuspendFunc:                         return mTrace.FindMethod("Suspend");
+    case ResumeFunc:                          return mTrace.FindMethod("Resume");
+    case LoadResourceFunc:                    return mTrace.FindMethod("LoadResource");
+    case LoadFileFunc:                        return mTrace.FindMethod("LoadFile");
+    case LoadShaderBinaryFileFunc:            return mTrace.FindMethod("LoadShaderBinaryFile");
+    case SaveShaderBinaryFileFunc:            return mTrace.FindMethod("SaveShaderBinaryFile");
+    case SaveFileFunc:                        return mTrace.FindMethod("SaveFile");
+    case CancelLoadFunc:                      return mTrace.FindMethod("CancelLoad");
+    case GetResourcesFunc:                    return mTrace.FindMethod("GetResources");
+    case IsLoadingFunc:                       return mTrace.FindMethod("IsLoading");
+    case SetDpiFunc:                          return mTrace.FindMethod("SetDpi");
+    case JoinLoaderThreadsFunc:               return mTrace.FindMethod("JoinLoaderThreads");
+  }
+  return false;
+}
+
+void TestPlatformAbstraction::SetGetTimeMicrosecondsResult(size_t sec, size_t usec)
+{
+  mSeconds = sec;
+  mMicroSeconds = usec;
+}
+
+void TestPlatformAbstraction::IncrementGetTimeResult(size_t milliseconds)
+{
+  mMicroSeconds += milliseconds * 1000u;
+  unsigned int additionalSeconds = mMicroSeconds / 1000000u;
+
+  mSeconds += additionalSeconds;
+  mMicroSeconds -= additionalSeconds * 1000000u;
+}
+
+void TestPlatformAbstraction::SetIsLoadingResult(bool result)
+{
+  mIsLoadingResult = result;
+}
+
+void TestPlatformAbstraction::ClearReadyResources()
+{
+  memset(&mResources, 0, sizeof(Resources));
+}
+
+void TestPlatformAbstraction::SetResourceLoaded(Integration::ResourceId  loadedId,
+                                                Integration::ResourceTypeId  loadedType,
+                                                Integration::ResourcePointer loadedResource)
+{
+  mResources.loaded = true;
+  mResources.loadedId = loadedId;
+  mResources.loadedType = loadedType;
+  mResources.loadedResource = loadedResource;
+}
+
+void TestPlatformAbstraction::SetResourceLoadFailed(Integration::ResourceId  id,
+                                                    Integration::ResourceFailure failure)
+{
+  mResources.loadFailed = true;
+  mResources.loadFailedId = id;
+  mResources.loadFailure = failure;
+}
+
+Integration::ResourceRequest* TestPlatformAbstraction::GetRequest()
+{
+  return mRequest;
+}
+
+void TestPlatformAbstraction::DiscardRequest()
+{
+  delete mRequest;
+  mRequest = NULL;
+}
+
+void TestPlatformAbstraction::SetClosestImageSize(const Vector2& size)
+{
+  mClosestSize = size;
+}
+
+void TestPlatformAbstraction::SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer )
+{
+  mLoadFileResult.loadResult = result;
+  if( result )
+  {
+    mLoadFileResult.buffer = buffer;
+  }
+}
+
+void TestPlatformAbstraction::SetSaveFileResult( bool result )
+{
+  mSaveFileResult = result;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h
new file mode 100644 (file)
index 0000000..bff5de9
--- /dev/null
@@ -0,0 +1,246 @@
+#ifndef __DALI_TEST_PLATFORM_ABSTRACTION_H__
+#define __DALI_TEST_PLATFORM_ABSTRACTION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+#include <cstring>
+#include <dali/public-api/images/image-operations.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/common/set-wrapper.h>
+#include <dali/integration-api/platform-abstraction.h>
+
+#include "test-trace-call-stack.h"
+
+
+namespace Dali
+{
+
+/**
+ * Concrete implementation of the platform abstraction class.
+ */
+class DALI_IMPORT_API TestPlatformAbstraction : public Dali::Integration::PlatformAbstraction
+{
+
+public:
+
+  struct Resources
+  {
+    bool                         loaded;
+    Integration::ResourceId      loadedId;
+    Integration::ResourceTypeId  loadedType;
+    Integration::ResourcePointer loadedResource;
+
+    bool                         loadFailed;
+    Integration::ResourceId      loadFailedId;
+    Integration::ResourceFailure loadFailure;
+  };
+
+  struct LoadFileResult
+  {
+    inline LoadFileResult()
+    : loadResult(false)
+    {
+
+    }
+
+    bool loadResult;
+    Dali::Vector< unsigned char> buffer;
+  };
+
+  /**
+   * Constructor
+   */
+  TestPlatformAbstraction();
+
+  /**
+   * Destructor
+   */
+  virtual ~TestPlatformAbstraction();
+
+  /**
+   * @copydoc PlatformAbstraction::GetTimeMicroseconds()
+   */
+  virtual void GetTimeMicroseconds(unsigned int &seconds, unsigned int &microSeconds);
+
+  /**
+   * @copydoc PlatformAbstraction::Suspend()
+   */
+  virtual void Suspend();
+
+  /**
+   * @copydoc PlatformAbstraction::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( const std::string& filename,
+                                                 ImageDimensions size,
+                                                 FittingMode::Type fittingMode,
+                                                 SamplingMode::Type samplingMode,
+                                                 bool orientationCorrection );
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                               ImageDimensions size,
+                                               FittingMode::Type fittingMode,
+                                               SamplingMode::Type samplingMode,
+                                               bool orientationCorrection );
+  /**
+   * @copydoc PlatformAbstraction::LoadResource()
+   */
+  virtual void LoadResource(const Integration::ResourceRequest& request);
+
+  /**
+   * @copydoc PlatformAbstraction::LoadResourceSynchronously()
+   */
+  virtual Integration::ResourcePointer LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath );
+
+  /**
+   * @copydoc PlatformAbstraction::DecodeBuffer()
+   */
+  virtual Integration::BitmapPtr DecodeBuffer( const Dali::Integration::ResourceType& resourceType, uint8_t * buffer, size_t size );
+
+  /**
+   * @copydoc PlatformAbstraction::CancelLoad()
+   */
+  virtual void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId);
+
+  /**
+   * @copydoc PlatformAbstraction::GetResources()
+   */
+  virtual void GetResources(Integration::ResourceCache& cache);
+
+  /**
+   * @copydoc PlatformAbstraction::IsLoading()
+   */
+  virtual bool IsLoading();
+
+  /**
+   * @copydoc PlatformAbstraction::GetDefaultFontSize()
+   */
+  virtual int GetDefaultFontSize() const;
+
+  /**
+   * @copydoc PlatformAbstraction::SetDpi()
+   */
+  virtual void SetDpi (unsigned int dpiHorizontal, unsigned int dpiVertical);
+
+  /**
+   * @copydoc PlatformAbstraction::LoadFile()
+   */
+  virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
+
+  /**
+   * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
+   */
+  virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer
+) const;
+
+  virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const { return true; }
+
+  /**
+   * @copydoc PlatformAbstraction::SaveFile()
+   */
+  virtual bool SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes) const;
+
+  virtual void JoinLoaderThreads();
+
+public: // TEST FUNCTIONS
+
+  // Enumeration of Platform Abstraction methods
+  typedef enum
+  {
+    GetTimeMicrosecondsFunc,
+    SuspendFunc,
+    ResumeFunc,
+    LoadResourceFunc,
+    SaveFileFunc,
+    LoadFileFunc,
+    LoadShaderBinaryFileFunc,
+    SaveShaderBinaryFileFunc,
+    CancelLoadFunc,
+    GetResourcesFunc,
+    IsLoadingFunc,
+    SetDpiFunc,
+    JoinLoaderThreadsFunc,
+  } TestFuncEnum;
+
+  /** Call this every test */
+  void Initialize();
+
+  inline void EnableTrace(bool enable) { mTrace.Enable(enable); }
+  inline void ResetTrace() { mTrace.Reset(); }
+  inline TraceCallStack& GetTrace() { return mTrace; }
+
+  bool WasCalled(TestFuncEnum func);
+
+  void SetGetTimeMicrosecondsResult(size_t sec, size_t usec);
+
+  void IncrementGetTimeResult(size_t milliseconds);
+
+  void SetIsLoadingResult(bool result);
+
+  void SetGetDefaultFontFamilyResult(std::string result);
+
+  void SetGetDefaultFontSizeResult(float result);
+
+  void SetGetFontPathResult(std::string& result);
+
+  void ClearReadyResources();
+
+  void SetResourceLoaded(Integration::ResourceId  loadedId,
+                         Integration::ResourceTypeId  loadedType,
+                         Integration::ResourcePointer loadedResource);
+
+  void SetResourceLoadFailed(Integration::ResourceId  id,
+                             Integration::ResourceFailure failure);
+
+  Integration::ResourceRequest* GetRequest();
+
+  void DiscardRequest();
+
+  void SetClosestImageSize(const Vector2& size);
+
+  void SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer );
+
+  void SetSaveFileResult( bool result );
+
+private:
+  mutable TraceCallStack        mTrace;
+  size_t                        mSeconds;
+  size_t                        mMicroSeconds;
+  bool                          mIsLoadingResult;
+  Resources                     mResources;
+  Integration::ResourceRequest* mRequest;
+  Vector2                       mSize;
+  Vector2                       mClosestSize;
+
+  LoadFileResult                mLoadFileResult;
+  bool                          mSaveFileResult;
+};
+
+} // Dali
+
+#endif /* __DALI_TET_PLATFORM_ABSTRACTION_H__ */
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
new file mode 100644 (file)
index 0000000..f3b04ad
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-render-controller.h"
+
+namespace Dali
+{
+
+TestRenderController::TestRenderController()
+{
+  Initialize();
+}
+
+TestRenderController::~TestRenderController()
+{
+}
+
+void TestRenderController::RequestUpdate()
+{
+  mRequestUpdateCalled = true;
+}
+
+void TestRenderController::RequestProcessEventsOnIdle()
+{
+  mRequestProcessEventsOnIdleCalled = true;
+}
+
+bool TestRenderController::WasCalled(TestRenderControllerFuncEnum func)
+{
+  switch(func)
+  {
+    case RequestUpdateFunc: return mRequestUpdateCalled;
+    case RequestProcessEventsOnIdleFunc: return mRequestProcessEventsOnIdleCalled;
+  }
+
+  return false;
+}
+
+void TestRenderController::Initialize()
+{
+  mRequestUpdateCalled = false;
+  mRequestProcessEventsOnIdleCalled = false;
+}
+
+
+} // namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h
new file mode 100644 (file)
index 0000000..b00fbf0
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __TEST_RENDER_CONTROLLER_H__
+#define __TEST_RENDER_CONTROLLER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/render-controller.h>
+
+namespace Dali
+{
+
+class DALI_IMPORT_API TestRenderController : public Dali::Integration::RenderController
+{
+public:
+  TestRenderController();
+  ~TestRenderController();
+
+  virtual void RequestUpdate();
+  virtual void RequestProcessEventsOnIdle();
+
+  typedef enum
+  {
+    RequestUpdateFunc,
+    RequestProcessEventsOnIdleFunc,
+  } TestRenderControllerFuncEnum;
+
+  bool WasCalled(TestRenderControllerFuncEnum func);
+  void Initialize();
+
+
+private:
+  bool mRequestUpdateCalled;
+  bool mRequestProcessEventsOnIdleCalled;
+};
+
+} // Dali
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h
new file mode 100644 (file)
index 0000000..68d50f2
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _TEST_TOUCH_UTILS_H_
+#define _TEST_TOUCH_UTILS_H_
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/actors/actor.h>
+
+namespace Dali
+{
+
+// Data for touch events
+struct TouchEventData
+{
+  TouchEventData()
+  : functorCalled(false),
+    receivedTouch(),
+    touchActor()
+  {
+  }
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    receivedTouch.points.clear();
+    receivedTouch.time = 0;
+
+    touchActor = NULL;
+  }
+
+  bool functorCalled;
+  TouchEvent receivedTouch;
+  Actor touchActor;
+};
+
+// Functor that sets the data when called
+struct TouchEventDataFunctor
+{
+  TouchEventDataFunctor(TouchEventData& data) : touchEventData(data) { }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    touchEventData.functorCalled = true;
+    touchEventData.touchActor = actor;
+    touchEventData.receivedTouch = touch;
+    return false;
+  }
+
+  // Generate a touch-event
+  Integration::TouchEvent GenerateSingleTouch( TouchPoint::State state, Vector2 screenPosition ) const
+  {
+    Integration::TouchEvent touchEvent;
+    touchEvent.points.push_back( TouchPoint ( 0, state, screenPosition.x, screenPosition.y ) );
+    return touchEvent;
+  }
+
+  TouchEventData& touchEventData;
+};
+
+
+} // namespace Dali
+
+#endif //  _TEST_TOUCH_UTILS_H_
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
new file mode 100644 (file)
index 0000000..921088b
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+/**
+ * Constructor
+ */
+TraceCallStack::TraceCallStack() : mTraceActive(false) { }
+
+/**
+ * Destructor
+ */
+TraceCallStack::~TraceCallStack() { }
+
+/**
+ * Turn on / off tracing
+ */
+void TraceCallStack::Enable(bool enable) { mTraceActive = enable; }
+
+bool TraceCallStack::IsEnabled() { return mTraceActive; }
+
+/**
+ * Push a call onto the stack if the trace is active
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ */
+void TraceCallStack::PushCall(std::string method, std::string params)
+{
+  if(mTraceActive)
+  {
+    std::vector< std::string > functionCall;
+    functionCall.push_back(method);
+    functionCall.push_back(params);
+    mCallStack.push_back( functionCall );
+  }
+}
+
+/**
+ * Search for a method in the stack
+ * @param[in] method The name of the method
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethod(std::string method) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i][0].compare(method) )
+    {
+      found = true;
+      break;
+    }
+  }
+  return found;
+}
+
+int TraceCallStack::CountMethod(std::string method) const
+{
+  int numCalls = 0;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i][0].compare(method) )
+    {
+      numCalls++;
+    }
+  }
+  return numCalls;
+}
+
+
+/**
+ * Search for a method in the stack with the given parameter list
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethodAndParams(std::string method, std::string params) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i][0].compare(method) && 0 == mCallStack[i][1].compare(params) )
+    {
+      found = true;
+      break;
+    }
+  }
+  return found;
+}
+
+/**
+ * Test if the given method and parameters are at a given index in the stack
+ * @param[in] index Index in the call stack
+ * @param[in] method Name of method to test
+ * @param[in] params A comma separated list of parameter values to test
+ */
+bool TraceCallStack::TestMethodAndParams(int index, std::string method, std::string params) const
+{
+  return ( 0 == mCallStack[index][0].compare(method) && 0 == mCallStack[index][1].compare(params) );
+}
+
+/**
+ * Reset the call stack
+ */
+void TraceCallStack::Reset()
+{
+  mCallStack.clear();
+}
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h
new file mode 100644 (file)
index 0000000..25b77f8
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __TEST_TRACE_CALL_STACK_H__
+#define __TEST_TRACE_CALL_STACK_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string>
+#include <vector>
+
+namespace Dali
+{
+
+/**
+ * Helper class to track method calls in the abstraction and search for them in test cases
+ */
+class TraceCallStack
+{
+public:
+  /**
+   * Constructor
+   */
+  TraceCallStack();
+
+  /**
+   * Destructor
+   */
+  ~TraceCallStack();
+
+  /**
+   * Turn on / off tracing
+   */
+  void Enable(bool enable);
+
+  bool IsEnabled();
+
+  /**
+   * Push a call onto the stack if the trace is active
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   */
+  void PushCall(std::string method, std::string params);
+
+
+  /**
+   * Search for a method in the stack
+   * @param[in] method The name of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethod(std::string method) const;
+
+  /**
+   * Count how many times a method was called
+   * @param[in] method The name of the method
+   * @return The number of times it was called
+   */
+  int CountMethod(std::string method) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndParams(std::string method, std::string params) const;
+
+  /**
+   * Test if the given method and parameters are at a given index in the stack
+   * @param[in] index Index in the call stack
+   * @param[in] method Name of method to test
+   * @param[in] params A comma separated list of parameter values to test
+   */
+  bool TestMethodAndParams(int index, std::string method, std::string params) const;
+
+  /**
+   * Reset the call stack
+   */
+  void Reset();
+
+  /**
+   * Get the call stack
+   * @return The call stack object (Vector of vector[2] of method/paramlist strings)
+   */
+  inline const std::vector< std::vector< std::string > >& GetCallStack() { return mCallStack; }
+
+private:
+  bool mTraceActive; ///< True if the trace is active
+  std::vector< std::vector< std::string > > mCallStack; ///< The call stack
+};
+
+} // namespace dali
+
+#endif //__TEST_TRACE_CALL_STACK_H__
diff --git a/automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp b/automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp
new file mode 100644 (file)
index 0000000..f84c7b3
--- /dev/null
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-adaptor-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "r";
+  bool optRerunFailed(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'r':
+        optRerunFailed = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Application.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Application.cpp
new file mode 100644 (file)
index 0000000..daaee0b
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_application_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_application_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( Application& app)
+  : initCalled( false ),
+    application( app )
+  {
+    application.InitSignal().Connect( this, &MyTestApp::Create );
+  }
+
+  void Create(Application& app)
+  {
+    initCalled = true;
+  }
+
+  void Quit()
+  {
+    application.Quit();
+  }
+
+  // Data
+  bool initCalled;
+  Application& application;
+};
+
+void ApplicationSignalCallback( Application& app )
+{
+}
+
+void ApplicationControlSignalCallback(Application&, void *)
+{
+}
+
+} // unnamed namespace
+
+int UtcDaliApplicationNew01(void)
+{
+  Application application = Application::New();
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew02(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew03(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv, "stylesheet" );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew04(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv, "stylesheet", Application::TRANSPARENT );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationCopyAndAssignment(void)
+{
+  Application application = Application::New();
+  Application copy( application );
+  DALI_TEST_CHECK( copy == application );
+
+  Application assigned;
+  DALI_TEST_CHECK( !assigned );
+  assigned = application;
+  DALI_TEST_CHECK( copy == assigned );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMainLoop01N(void)
+{
+  Application application;
+
+  try
+  {
+    application.MainLoop();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMainLoop02N(void)
+{
+  Application application;
+
+  try
+  {
+    application.MainLoop( Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowerN(void)
+{
+  Application application;
+
+  try
+  {
+    application.Lower();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationQuitN(void)
+{
+  Application application;
+
+  try
+  {
+    application.Quit();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationAddIdleN(void)
+{
+  Application application;
+
+  try
+  {
+    CallbackBase* callback = NULL;
+    application.AddIdle( callback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetWindowN(void)
+{
+  Application application;
+
+  try
+  {
+    (void) application.GetWindow();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationReplaceWindowN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ReplaceWindow( PositionSize(), "window" );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationSetViewModeN(void)
+{
+  Application application;
+
+  try
+  {
+    application.SetViewMode( STEREO_VERTICAL );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetViewModeN(void)
+{
+  Application application;
+
+  try
+  {
+    (void) application.GetViewMode();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationSetStereoBaseN(void)
+{
+  Application application;
+
+  try
+  {
+    application.SetStereoBase( 1.0f );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetStereoBaseN(void)
+{
+  Application application;
+
+  try
+  {
+    (void) application.GetStereoBase();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationInitSignalP(void)
+{
+  Application application = Application::New();
+  application.InitSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationInitSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.InitSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationTerminateSignalP(void)
+{
+  Application application = Application::New();
+  application.TerminateSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationTerminateSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.TerminateSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationPauseSignalP(void)
+{
+  Application application = Application::New();
+  application.PauseSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationPauseSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.PauseSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResumeSignalP(void)
+{
+  Application application = Application::New();
+  application.ResumeSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResumeSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResumeSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResetSignalP(void)
+{
+  Application application = Application::New();
+  application.ResetSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResetSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResetSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResizeSignalP(void)
+{
+  Application application = Application::New();
+  application.ResizeSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResizeSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResizeSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationlControlSignalP(void)
+{
+  Application application = Application::New();
+  application.AppControlSignal().Connect( &ApplicationControlSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationlControlSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.AppControlSignal().Connect( &ApplicationControlSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLanguageChangedSignalP(void)
+{
+  Application application = Application::New();
+  application.LanguageChangedSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLanguageChangedSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.LanguageChangedSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationRegionChangedSignalP(void)
+{
+  Application application = Application::New();
+  application.RegionChangedSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationRegionChangedSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.RegionChangedSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationBatteryLowSignalP(void)
+{
+  Application application = Application::New();
+  application.BatteryLowSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationBatteryLowSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.BatteryLowSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMemoryLowSignalP(void)
+{
+  Application application = Application::New();
+  application.MemoryLowSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMemoryLowSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.MemoryLowSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Key.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Key.cpp
new file mode 100644 (file)
index 0000000..51d7bc0
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <map>
+#include <string.h>
+#include <iostream>
+
+// CLASS HEADER
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_adaptor_key_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_adaptor_key_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Copied from key-impl.h
+struct KeyLookup
+{
+  const char* keyName;          ///< XF86 key name
+  const Dali::KEY daliKeyCode;  ///< Dali key code
+  const bool  deviceButton;     ///< Whether the key is from a button on the device
+};
+
+// Common keys for all platforms
+KeyLookup KeyLookupTable[]=
+{
+  { "Escape",                DALI_KEY_ESCAPE,          false },  // item not defined in utilX
+  { "Menu",                  DALI_KEY_MENU,            false },  // item not defined in utilX
+
+  // Now the key names are used as literal string not defined symbols,
+  // since these definition in utilX.h is deprecated and we're guided not to use them
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+};
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable))/ (sizeof(KeyLookup));
+
+
+// Generate a KeyPressEvent to send to Core
+Dali::KeyEvent GenerateKeyPress( const std::string& keyName )
+{
+  KeyEvent keyPress;
+  keyPress.keyPressedName = keyName;
+  return keyPress;
+}
+
+int UtcDaliKeyIsKey(void)
+{
+  TestApplication application;
+
+  for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+  {
+    tet_printf( "Checking %s", KeyLookupTable[i].keyName );
+    DALI_TEST_CHECK( IsKey( GenerateKeyPress( KeyLookupTable[i].keyName ), KeyLookupTable[i].daliKeyCode ) );
+  }
+  END_TEST;
+}
+
+int UtcDaliKeyIsKeyNegative(void)
+{
+  TestApplication application;
+
+  // Random value
+  DALI_TEST_CHECK( IsKey( GenerateKeyPress( "invalid-key-name" ), DALI_KEY_MUTE ) == false );
+
+  // Compare with another key value
+  for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+  {
+    tet_printf( "Checking %s", KeyLookupTable[i].keyName );
+    DALI_TEST_CHECK( IsKey( GenerateKeyPress( KeyLookupTable[i].keyName ), KeyLookupTable[ ( i + 1 ) % KEY_LOOKUP_COUNT ].daliKeyCode ) == false );
+  }
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp b/automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp
new file mode 100644 (file)
index 0000000..bec87e3
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <map>
+#include <string.h>
+#include <iostream>
+
+// CLASS HEADER
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+
+extern int gArgc;
+extern char ** gArgv;
+
+using namespace Dali;
+
+void utc_dali_adaptor_keygrab_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_adaptor_keygrab_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Copied from key-impl.cpp
+struct KeyLookup
+{
+  const char* keyName;      ///< X string representation
+  const int   daliKeyCode;  ///< Dali Enum Representation
+  const bool  deviceButton; ///< Whether the key is from a button on the device
+};
+
+// Taken from key-impl.cpp
+KeyLookup TestKeyLookupTable[]=
+{
+  { "Escape",                DALI_KEY_ESCAPE,          false },  // item not defined in utilX
+  { "Menu",                  DALI_KEY_MENU,            false },  // item not defined in utilX
+
+  // Now the key names are used as literal string not defined symbols,
+  // since these definition in utilX.h is deprecated and we're guided not to use them
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Send",              DALI_KEY_SEND,            true  },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( TestKeyLookupTable))/ (sizeof(KeyLookup));
+
+enum TEST_TYPE
+{
+  GRAB_KEY_P,
+  UNGRAB_KEY_P,
+  UNGRAB_KEY_N,
+  GRAB_KEY_TOPMOST_P,
+  UNGRAB_KEY_TOPMOST_P
+};
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( Application& app, int type )
+  : mApplication( app ),
+    mTestType( type )
+  {
+    mApplication.InitSignal().Connect( this, &MyTestApp::OnInit );
+  }
+
+  void OnInit(Application& app)
+  {
+    mTimer = Timer::New( 500 );
+    mTimer.TickSignal().Connect( this, &MyTestApp::Tick );
+    mTimer.Start();
+
+    ExcuteTest();
+  }
+
+  bool Tick()
+  {
+    mTimer.Stop();
+    mApplication.Quit();
+    return true;
+  }
+
+  void ExcuteTest()
+  {
+    switch (mTestType)
+    {
+      case GRAB_KEY_P:
+        TestGrabKeyP();
+        break;
+      case UNGRAB_KEY_P:
+        TestUngrabKeyP();
+        break;
+      case UNGRAB_KEY_N:
+        TestUngrabKeyN();
+        break;
+      case GRAB_KEY_TOPMOST_P:
+        TestGrabKeyTopmostP();
+        break;
+      case UNGRAB_KEY_TOPMOST_P:
+        TestUngrabKeyTopmostP();
+        break;
+    }
+  }
+
+  void TestGrabKeyP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKey( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode, KeyGrab::TOPMOST ) );
+      DALI_TEST_CHECK( KeyGrab::GrabKey( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode, KeyGrab::SHARED ) );
+    }
+  }
+
+  void TestUngrabKeyP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKey( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode, KeyGrab::TOPMOST ) );
+      DALI_TEST_CHECK( KeyGrab::UngrabKey( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+    }
+  }
+
+  void TestUngrabKeyN()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::UngrabKey( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) == false );
+    }
+  }
+
+  void TestGrabKeyTopmostP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+    }
+  }
+
+  void TestUngrabKeyTopmostP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+      DALI_TEST_CHECK( KeyGrab::UngrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+    }
+  }
+
+  // Data
+  Application& mApplication;
+  int mTestType;
+  Timer mTimer;
+};
+
+int UtcDaliKeyGrabGrabKeyP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, GRAB_KEY_P );
+  application.MainLoop();
+  END_TEST;
+}
+
+int UtcDaliKeyGrabUngrabKeyP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, UNGRAB_KEY_P );
+  application.MainLoop();
+  END_TEST;
+}
+
+int UtcDaliKeyGrabUngrabKeyN(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, UNGRAB_KEY_N );
+  application.MainLoop();
+  END_TEST;
+}
+
+int UtcDaliKeyGrabGrabKeyTopmostP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, GRAB_KEY_TOPMOST_P );
+  application.MainLoop();
+  END_TEST;
+}
+
+int UtcDaliKeyGrabUngrabKeyTopmostP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, UNGRAB_KEY_TOPMOST_P );
+  application.MainLoop();
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp b/automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp
new file mode 100644 (file)
index 0000000..679409a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+#include <Ecore_X.h>
+
+using namespace Dali;
+
+
+void utc_dali_native_image_source_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_native_image_source_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliNativeImageSourceNewN(void)
+{
+  unsigned int width = 256u;
+  unsigned int heigth = 256u;
+
+  try
+  {
+    NativeImageSourcePtr nativeImageSource = NativeImageSource::New(width, heigth, NativeImageSource::COLOR_DEPTH_DEFAULT );
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_ASSERT(e, "Adaptor::IsAvailable()", TEST_LOCATION);
+  }
+  catch(...)
+  {
+    tet_printf("Assertion test failed - wrong Exception\n" );
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-SingletonService.cpp b/automated-tests/src/dali-adaptor/utc-Dali-SingletonService.cpp
new file mode 100644 (file)
index 0000000..2ceb1f0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+
+using namespace Dali;
+
+namespace
+{
+
+class TestHandle : public BaseHandle
+{
+public:
+  TestHandle() {}
+  TestHandle( BaseObject* object ) : BaseHandle( object ) {}
+};
+
+class TestObject : public BaseObject
+{
+};
+
+} // unnamed namespace
+
+void utc_dali_singleton_service_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_singleton_service_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliSingletonServiceGet(void)
+{
+  // Attempt to retrieve SingletonService before creating application
+  SingletonService singletonService;
+  singletonService = SingletonService::Get();
+  DALI_TEST_CHECK( !singletonService );
+
+  // Create Application class, should be able to retrieve SingletonService now
+  Application application = Application::New();
+  singletonService = SingletonService::Get();
+  DALI_TEST_CHECK( singletonService );
+
+  END_TEST;
+}
+
+int UtcDaliSingletonServiceRegisterAndGetSingleton(void)
+{
+  Application application = Application::New();
+  SingletonService singletonService( SingletonService::Get() );
+
+  // Attempt to register an empty handle
+  TestHandle handle;
+  singletonService.Register( typeid( handle ), handle );
+  DALI_TEST_CHECK( !singletonService.GetSingleton( typeid( handle ) ) );
+
+  // Create an actor instance and retrieve, should be valid this time
+  handle = TestHandle( new TestObject );
+  singletonService.Register( typeid( handle ), handle );
+  DALI_TEST_CHECK( singletonService.GetSingleton( typeid( handle ) ) );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp
new file mode 100644 (file)
index 0000000..ecd4638
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <dali/dali.h>
+#include <Ecore.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_timer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_timer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+bool ecore_timer_running = false;
+Ecore_Task_Cb timer_callback_func=NULL;
+const void* timer_callback_data=NULL;
+bool main_loop_can_run = false;
+intptr_t timerId = 0; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_timer_add below without compilation warnings
+}// anon namespace
+
+extern "C"
+{
+Ecore_Timer* ecore_timer_add(double in,
+                             Ecore_Task_Cb func,
+                             const void   *data)
+{
+  ecore_timer_running = true;
+  timer_callback_func = func;
+  timer_callback_data = data;
+  timerId+=8;
+  return (Ecore_Timer*)timerId;
+}
+
+void* ecore_timer_del(Ecore_Timer *timer)
+{
+  ecore_timer_running = false;
+  timer_callback_func = NULL;
+  return NULL;
+}
+
+}
+
+namespace
+{
+
+void test_ecore_main_loop_begin()
+{
+  if(timer_callback_func != NULL)
+  {
+    main_loop_can_run = true;
+    while( main_loop_can_run )
+    {
+      if( ! timer_callback_func(const_cast<void*>(timer_callback_data)) )
+        break;
+    }
+  }
+}
+
+void test_ecore_main_loop_quit()
+{
+  timer_callback_func = NULL;
+  main_loop_can_run = false;
+}
+
+
+/**
+ * small class to test timer signal
+ */
+class TimerTestClass : public ConnectionTracker
+{
+public:
+
+  TimerTestClass(bool repeat):mTimerCalled(false),mReturnContiune(repeat) {}
+
+  bool Tick()
+  {
+    tet_printf("timer ticked\n");
+    mTimerCalled = true;
+    // quit the main loop otherwise we'll never return to tet
+    test_ecore_main_loop_quit();
+    return mReturnContiune;
+  }
+  bool mTimerCalled;    // whether tick has been called or not
+  bool mReturnContiune; // whether to return true / false to continue
+
+};
+
+} // anon namespace
+
+
+// Positive test case for a method
+int UtcDaliTimerCreation(void)
+{
+ // TestApplication application;
+  tet_printf("timer creation \n");
+  Timer timer = Timer::New(300);
+
+  DALI_TEST_CHECK( timer );
+
+  DALI_TEST_CHECK( timer.GetInterval() == 300);
+
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedStart(void)
+{
+  tet_printf("unintialized timer start \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->Start();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedStop(void)
+{
+  tet_printf("unintialized timer stop \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->Stop();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedGetInterval(void)
+{
+  tet_printf("unintialized get interval \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->GetInterval();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedSetInterval(void)
+{
+  tet_printf("unintialized set interval \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->SetInterval(10);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedIsRunning(void)
+{
+  tet_printf("unintialized is running \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->IsRunning();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+
+int UtcDaliTimerUnitializedSignalTick(void)
+{
+  tet_printf("unintialized SignalTick \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    TimerTestClass testClass(true);// = new TimerTestClass(true);
+
+    timer->TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerSetInterval(void)
+{
+  tet_printf("timer set interval \n");
+  Timer timer = Timer::New(10);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 10);
+
+  timer.SetInterval(5000);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 5000);
+
+  END_TEST;
+}
+
+int UtcDaliTimerCopyConstructor(void)
+{
+  tet_printf("timer copy constructor \n");
+  Timer timer = Timer::New(10);
+
+  Timer anotherTimer( timer );
+
+  DALI_TEST_CHECK( anotherTimer.GetInterval() == 10);
+  END_TEST;
+}
+
+int UtcDaliTimerAssignmentOperator(void)
+{
+  tet_printf("assignmnet constructor \n");
+
+  Timer timer = Timer::New(10);
+
+  DALI_TEST_CHECK( timer );
+
+  Timer anotherTimer = Timer::New(40);
+
+  DALI_TEST_CHECK(anotherTimer.GetInterval() == 40);
+
+  tet_printf("timer 1 interval %d, \n",anotherTimer.GetInterval());
+  tet_printf("timer 2 interval %d, \n",timer.GetInterval());
+
+  DALI_TEST_CHECK(timer != anotherTimer);
+
+  timer = anotherTimer;
+
+  DALI_TEST_CHECK(timer == anotherTimer);
+
+  tet_printf("timer 1 interval %d, \n",timer.GetInterval());
+  tet_printf("timer 2 interval %d, \n",anotherTimer.GetInterval());
+
+  DALI_TEST_CHECK(timer.GetInterval() == 40);
+
+  END_TEST;
+}
+
+int UtcDaliTimerIsRunning(void)
+{
+  tet_printf("timer is running \n");
+
+  Timer timer = Timer::New(100);
+
+  timer.Start();
+
+  DALI_TEST_CHECK( timer.IsRunning() );
+
+  timer.Stop();
+
+  DALI_TEST_CHECK( timer.IsRunning() == false );
+
+  END_TEST;
+}
+
+int UtcDaliTimerSignalTickContinue(void)
+{
+  tet_printf("timer call back\n");
+
+  Timer timer = Timer::New(100);
+  TimerTestClass testClass(true);
+
+  timer.TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+
+  timer.Start();
+
+  test_ecore_main_loop_begin();
+
+  DALI_TEST_CHECK( testClass.mTimerCalled );
+
+  END_TEST;
+}
+
+int UtcDaliTimerSignalTickStop(void)
+{
+  Timer timer = Timer::New(100);
+  TimerTestClass testClass(false);
+
+  timer.TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+
+  timer.Start();
+
+  test_ecore_main_loop_begin();
+
+  DALI_TEST_CHECK( testClass.mTimerCalled );
+
+  END_TEST;
+}
+
+int UtcDaliTimerReset(void)
+{
+  Timer timer = Timer::New(100);
+
+  DALI_TEST_CHECK(timer);
+
+  timer.Reset();
+
+  DALI_TEST_CHECK(!timer);
+
+  END_TEST;
+}
+
+int UtcDaliTimerDownCastP(void)
+{
+  Timer timer = Timer::New(100);
+  Timer cast = Timer::DownCast( timer );
+
+  DALI_TEST_CHECK( cast );
+
+  END_TEST;
+}
+
+int UtcDaliTimerDownCastN(void)
+{
+  Timer timer;
+  Timer cast = Timer::DownCast( timer );
+
+  DALI_TEST_CHECK( ! cast );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp
new file mode 100644 (file)
index 0000000..d286765
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_ttsplayer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_ttsplayer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+} // unnamed namespace
+
+int UtcDaliTtsPlayerConstructorP(void)
+{
+  Dali::TtsPlayer player;
+  DALI_TEST_CHECK( !player );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerCopyConstructorP(void)
+{
+  Dali::TtsPlayer player;
+  Dali::TtsPlayer copy( player );
+  DALI_TEST_CHECK( copy == player );
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerAssignmentOperatorP(void)
+{
+  Dali::TtsPlayer player;
+  Dali::TtsPlayer copy;
+  DALI_TEST_CHECK( ! copy );
+  copy = player;
+  DALI_TEST_CHECK( copy == player );
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerDestructorP(void)
+{
+  Dali::TtsPlayer* player = new Dali::TtsPlayer();
+  delete player;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerConstructorFromInternalPointerN(void)
+{
+  Internal::Adaptor::TtsPlayer* internalPlayer = NULL;
+  Dali::TtsPlayer player(internalPlayer);
+  DALI_TEST_CHECK( !player ); // Should not reach here!
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerGetP(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+  DALI_TEST_CHECK( !player );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerPlayN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Play("text");
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerStopN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Stop();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerPauseN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Pause();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerResumeN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Resume();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerGetStateN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    Dali::TtsPlayer::State state = player.GetState();
+    tet_printf( "Error: TtsPlayer state = %d, expected exception\n", (unsigned int)state );
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Window.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Window.cpp
new file mode 100644 (file)
index 0000000..c917d7b
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <Ecore_X.h>
+#include <devel-api/adaptor-framework/drag-and-drop-detector.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_window_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_window_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+intptr_t screenId = 0; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_x_default_screen_get below without compilation warnings
+
+} // unnamed namespace
+
+extern "C"
+{
+
+Ecore_X_Screen* ecore_x_default_screen_get(void)
+{
+  screenId += 8;
+  return (Ecore_X_Screen*)screenId;
+}
+
+void ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h)
+{
+ *w = 100;
+ *h = 100;
+}
+
+Ecore_X_Window ecore_x_window_argb_new(Ecore_X_Window parent, int x, int y, int w, int h)
+{
+  return 0;
+}
+
+}
+
+int UtcDaliWindowConstructorP(void)
+{
+  Dali::Window window;
+  DALI_TEST_CHECK( !window );
+  END_TEST;
+}
+
+int UtcDaliWindowCopyConstructorP(void)
+{
+  Dali::Window window;
+  Dali::Window copy( window );
+  DALI_TEST_CHECK( copy == window );
+
+  END_TEST;
+}
+
+int UtcDaliWindowConstructorFromInternalPointerN(void)
+{
+  Internal::Adaptor::Window* internalWindow = NULL;
+  Dali::Window window(internalWindow);
+  DALI_TEST_CHECK( !window ); // Should not reach here!
+
+  END_TEST;
+}
+
+int UtcDaliWindowAssignmentOperatorP(void)
+{
+  const Dali::Window window;
+  Dali::Window copy;
+  DALI_TEST_CHECK( ! copy );
+  copy = window;
+  DALI_TEST_CHECK( copy == window );
+
+  END_TEST;
+}
+
+int UtcDaliWindowDestructorP(void)
+{
+  Dali::Window* window = new Dali::Window();
+  delete window;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliWindowNewN(void)
+{
+  // Attempt to create a new window
+  try
+  {
+    PositionSize windowPosition(0, 0, 0, 0);
+    Dali::Window window = Dali::Window::New( windowPosition, "test-window", true );
+
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "Failed to create X window", TEST_LOCATION );
+  }
+
+  // Attempt to create a new window
+  try
+  {
+    PositionSize windowPosition(0, 0, 0, 0);
+    Dali::Window window = Dali::Window::New( windowPosition, "test-window", "test-window-class", true );
+
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "Failed to create X window", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowShowIndicatorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.ShowIndicator(Dali::Window::VISIBLE);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetIndicatorBgOpacityN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetIndicatorBgOpacity(Dali::Window::OPAQUE);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRotateIndicatorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.RotateIndicator(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetClassN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetClass("window-name", "window-class");
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRaiseN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Raise();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowLowerN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Lower();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowActivateN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Activate();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowAddAvailableOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.AddAvailableOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRemoveAvailableOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.RemoveAvailableOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetPreferredOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetPreferredOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetPreferredOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    Dali::Window::WindowOrientation orientation = window.GetPreferredOrientation();
+    DALI_TEST_CHECK( orientation == Dali::Window::PORTRAIT ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetDragAndDropDetectorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    DragAndDropDetector detector = window.GetDragAndDropDetector();
+    DALI_TEST_CHECK( !detector ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetNativeHandleN(void)
+{
+  Dali::Window window;
+  try
+  {
+    Dali::Any handle = window.GetNativeHandle();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowIndicatorVisibilityChangedSignalN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.IndicatorVisibilityChangedSignal();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+
+
+
diff --git a/automated-tests/src/dali-platform-abstraction/CMakeLists.txt b/automated-tests/src/dali-platform-abstraction/CMakeLists.txt
new file mode 100644 (file)
index 0000000..df6910e
--- /dev/null
@@ -0,0 +1,54 @@
+SET(PKG_NAME "dali-platform-abstraction")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-platform-abstraction")
+
+SET(TC_SOURCES
+    utc-image-loading-load-completion.cpp
+    utc-image-loading-cancel-all-loads.cpp
+    utc-image-loading-cancel-some-loads.cpp
+)
+
+LIST(APPEND TC_SOURCES
+    resource-collector.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-harness.cpp
+    ../dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
+    tct-dali-platform-abstraction-core.cpp
+    utc-image-loading-common.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali
+)
+
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror=return-type" )
+
+# Shouldn't have to do this!
+# But CMake's new auto-escape quote policy doesn't work right.
+CMAKE_POLICY(SET CMP0005 OLD)
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ../../../adaptors/tizen
+    ../../../platform-abstractions/tizen
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-adaptor/dali-test-suite-utils
+    /usr/include/freetype2
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-platform-abstraction/resource-collector.cpp b/automated-tests/src/dali-platform-abstraction/resource-collector.cpp
new file mode 100644 (file)
index 0000000..799d4c6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "resource-collector.h"
+#include "tizen-platform-abstraction.h"
+#include <dali/integration-api/debug.h>
+#include <unistd.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+using namespace Dali::Integration;
+
+ResourceCollector::ResourceCollector() :
+  mGrandTotalCompletions(0),
+  mGrandTotalNotifications(0)
+{
+}
+
+ResourceCollector::~ResourceCollector() {}
+
+void ResourceCollector::LoadResponse( Dali::Integration::ResourceId id, Dali::Integration::ResourceTypeId type, Dali::Integration::ResourcePointer resource, Dali::Integration::LoadStatus status )
+{
+  ++mGrandTotalNotifications;
+  if( status == RESOURCE_COMPLETELY_LOADED )
+  {
+    DALI_ASSERT_DEBUG( mCompletionCounts.find(id) == mCompletionCounts.end() && "A resource can only complete once." );
+    mCompletionStatuses[id] = true;
+    ++mCompletionCounts[id];
+    ++mSuccessCounts[id];
+    mCompletionSequence.push_back( id );
+    ++mGrandTotalCompletions;
+  }
+}
+
+void ResourceCollector::LoadFailed( Dali::Integration::ResourceId id, Dali::Integration::ResourceFailure failure )
+{
+  mCompletionStatuses[id] = false;
+  ++mFailureCounts[id];
+  mCompletionSequence.push_back( id );
+  ++mGrandTotalCompletions;
+  ++mGrandTotalNotifications;
+}
+
+void PollForNotification( ResourceCollector& collector, Integration::PlatformAbstraction&  abstraction, const unsigned maxPolls )
+{
+  // Poll for at least one completed or partially completed load:
+  const unsigned outstandingNotifications = collector.mGrandTotalNotifications;
+  for( unsigned poll = 0; poll < maxPolls; ++poll )
+  {
+    abstraction.GetResources( collector );
+    if( collector.mGrandTotalNotifications > outstandingNotifications )
+    {
+      break;
+    }
+    usleep( 3 ); //< Wait 3 microseconds each time around.
+  }
+}
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
diff --git a/automated-tests/src/dali-platform-abstraction/resource-collector.h b/automated-tests/src/dali-platform-abstraction/resource-collector.h
new file mode 100644 (file)
index 0000000..7a4b2dd
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_
+#define __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/dali.h>
+#include <dali/integration-api/resource-cache.h>
+
+#include <map>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class PlatformAbstraction;
+}
+
+namespace Internal
+{
+namespace Platform
+{
+  /** Stores true for success and false for a failure for each completed
+   *  resource id.*/
+  typedef std::map<Integration::ResourceId, bool> ResourceStatusMap;
+  /** Stores an integer counter for a resource ID, e.g., to count the number of
+   *  times a load or a fail is reported.*/
+  typedef std::map<Integration::ResourceId, unsigned> ResourceCounterMap;
+  /** Used to track the order in which a sequence of requests is completed.*/
+  typedef std::vector<Integration::ResourceId> ResourceSequence;
+
+/**
+ * @brief Used for platform testing to record the result of resource requests
+ * initiated by tests.
+ */
+class ResourceCollector : public Integration::ResourceCache
+{
+public:
+
+  ResourceCollector();
+  virtual ~ResourceCollector();
+
+  virtual void LoadResponse(Dali::Integration::ResourceId id, Dali::Integration::ResourceTypeId type, Dali::Integration::ResourcePointer resource, Dali::Integration::LoadStatus status);
+
+  virtual void LoadFailed(Dali::Integration::ResourceId id, Dali::Integration::ResourceFailure failure);
+
+  // Data:
+  /** Record of the status of each completed resource. */
+  ResourceStatusMap mCompletionStatuses;
+  /** Record of how many times each resource completed (every value should be 1,
+   *  else we are broken). */
+  ResourceCounterMap mCompletionCounts;
+  /** Record of how many times each resource succeeded (every value should be 0 or
+   *  1, else we are broken). */
+  ResourceCounterMap mSuccessCounts;
+  /** Record of how many times each resource failed (every value should be 0 or 1,
+   * else we are broken).
+   * Only resource IDs that correspond to deliberately unloadable resources
+   * should have counts other than 0. */
+  ResourceCounterMap mFailureCounts;
+  /** Remember the order of request completions so request priority can be tested. */
+  ResourceSequence mCompletionSequence;
+  /** Count of all successes and failures.*/
+  unsigned mGrandTotalCompletions;
+  /** Count of all successes, failures, loading notifications and partially loaded notifications.*/
+  unsigned mGrandTotalNotifications;
+
+};
+
+/**
+ * Helper to poll the abstraction for notifications assuming loads have been
+ * issued to it previously and are in-flight.
+ */
+void PollForNotification( ResourceCollector& collector, Integration::PlatformAbstraction&  abstraction, const unsigned maxPolls = 100 );
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* __DALI_ADAPTOR_TCT_RESOURCE_COLLECTOR_H_ */
diff --git a/automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp b/automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp
new file mode 100644 (file)
index 0000000..0dba0c2
--- /dev/null
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-platform-abstraction-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "r";
+  bool optRerunFailed(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'r':
+        optRerunFailed = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    result = TestHarness::RunAllInParallel(argv[0], tc_array, optRerunFailed);
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-all-loads.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-all-loads.cpp
new file mode 100644 (file)
index 0000000..aa4d8b5
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "utc-image-loading-common.h"
+
+void utc_image_loading_cancel_all_loads_startup(void)
+{
+  utc_dali_loading_startup();
+}
+
+void utc_image_loading_cancel_all_loads_cleanup(void)
+{
+  utc_dali_loading_cleanup();
+}
+
+/**
+ * @brief Test case for load cancellation.
+ *
+ * Load lots of images in batches, cancelling all in a batch after a small delay to
+ * allow the first of a batch to be launched before cancellation starts.
+ * Assert that all loads issued are either completed or cancelled.
+ *
+ * @note Many loads will succeed despite our cancellations due to the coarse
+ * granularity of the waits we introduce after loading each batch. That is
+ * expected.
+ */
+int UtcDaliCancelAllLoads(void)
+{
+  tet_printf( "Running load cancel-all test.\n" );
+
+  DALI_ASSERT_ALWAYS( gAbstraction != 0 );
+
+  // Start a bunch of loads that should work:
+
+  Dali::Integration::LoadResourcePriority priority = LoadPriorityNormal;
+  unsigned loadsLaunched = 0;
+  Dali::Internal::Platform::ResourceCollector resourceSink;
+
+  for( unsigned loadGroup = 0; loadGroup < NUM_CANCELLED_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
+  {
+    // Issue load requests for a batch of images:
+    for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
+    {
+      const ImageParameters & loadParams = gCancelAttributes[ loadsLaunched % gCancelAttributes.size() ];
+      const BitmapResourceType bitmapResourceType( loadParams.first, loadParams.second.first, loadParams.second.second.first, loadParams.second.second.second );
+      const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
+      gAbstraction->LoadResource( ResourceRequest( resourceId, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
+      loadsLaunched += 1;
+    }
+
+    // Poll for at least one completed load so we have a good chance of catching an
+    // in-flight load as we run through the cancellations further below:
+    PollForNotification( resourceSink, *gAbstraction, 100 );
+
+    // Cancel all the launched loads in the batch from oldest to newest:
+    for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
+    {
+      const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
+      gAbstraction->CancelLoad( resourceId, ResourceBitmap );
+    }
+  }
+
+  // Drain the completed loads:
+
+  unsigned lastNotifications = -1;
+  for( unsigned i = 0; resourceSink.mGrandTotalCompletions < loadsLaunched && resourceSink.mGrandTotalNotifications != lastNotifications; )
+  {
+    lastNotifications = resourceSink.mGrandTotalNotifications;
+    gAbstraction->GetResources( resourceSink );
+
+    ++i;
+    if( i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched )
+    {
+      usleep( 1000 * 10 );
+    }
+    else
+    {
+      break;
+    }
+  }
+
+  // Check the loads completed as expected:
+
+  tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
+  DALI_TEST_CHECK( loadsLaunched > resourceSink.mGrandTotalCompletions );
+  DALI_TEST_CHECK( loadsLaunched > resourceSink.mSuccessCounts.size() );
+  DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
+
+  // Check that each success was reported exactly once:
+  for( ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
+  {
+    DALI_TEST_CHECK( it->second == 1u );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-some-loads.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-loading-cancel-some-loads.cpp
new file mode 100644 (file)
index 0000000..9a6d98e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "utc-image-loading-common.h"
+
+void utc_image_loading_cancel_some_loads_startup(void)
+{
+  utc_dali_loading_startup();
+}
+
+void utc_image_loading_cancel_some_loads_cleanup(void)
+{
+  utc_dali_loading_cleanup();
+}
+
+/**
+ * @brief Test case for load cancellation.
+ *
+ * Load lots, cancel a subset and be sure the wrong loads are never cancelled
+ * and that all loads issued are either completed or cancelled.
+ */
+int UtcDaliCancelSomeLoads(void)
+{
+  tet_printf( "Running load cancel load subset test.\n" );
+
+  DALI_ASSERT_ALWAYS( gAbstraction != 0 );
+
+  // Start a bunch of loads that should work:
+
+  Dali::Integration::LoadResourcePriority priority = LoadPriorityNormal;
+  unsigned loadsLaunched = 0;
+
+  std::set<Integration::ResourceId> cancelledLoadSet;
+  Dali::Internal::Platform::ResourceCollector resourceSink;
+
+  for( unsigned loadGroup = 0; loadGroup < NUM_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
+  {
+    const unsigned preIterationCompletions = resourceSink.mGrandTotalCompletions;
+
+    // Issue load requests for a batch of images:
+    for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
+    {
+      const ImageParameters & loadParams = gCancelAttributes[ loadsLaunched % gCancelAttributes.size() ];
+      const BitmapResourceType bitmapResourceType( loadParams.first, loadParams.second.first, loadParams.second.second.first, loadParams.second.second.second );
+      const ResourceId resourceId = loadGroup * NUM_VALID_IMAGES + validImage + 1;
+      gAbstraction->LoadResource( ResourceRequest( resourceId, bitmapResourceType, VALID_IMAGES[validImage], priority ) );
+      loadsLaunched += 1;
+    }
+
+    // Let the first image in the batch start to load so we can try to cancel it in-flight:
+    usleep( 1 * 1000 ); //< 1 ms is enough to let an image start to load.
+    ///@Note: The log should show cancellations of many in-flight loads in desktop builds with info-level logging enabled (e.g., "INFO: DALI: : CheckForCancellation: Cancelled in-flight resource (21)."). If it doesn't, the above delay may need to be adjusted.
+
+    // Cancel just two loads (hopefully one in-flight and one queued):
+
+    // Cancel first load, hopefully while it is in-flight:
+    const ResourceId cancelledInFlight = loadGroup * NUM_VALID_IMAGES + 1;
+    gAbstraction->CancelLoad( cancelledInFlight, ResourceBitmap );
+    cancelledLoadSet.insert( cancelledInFlight );
+
+    // Cancel second load, that is still queued:
+    const ResourceId cancelledFromQueue = loadGroup * NUM_VALID_IMAGES + NUM_VALID_IMAGES;
+    gAbstraction->CancelLoad( cancelledFromQueue, ResourceBitmap );
+    cancelledLoadSet.insert( cancelledFromQueue );
+
+    // Drain a group worth of images so the cancellations hit in-flight loads on the next iteration:
+    for( unsigned i = 0; i < NUM_VALID_IMAGES * 1000 * 1000 * 10 / (5 * 1000)  && resourceSink.mGrandTotalCompletions < preIterationCompletions + NUM_VALID_IMAGES - 2; ++i )
+    {
+      gAbstraction->GetResources( resourceSink );
+      usleep( 5 * 1000 );
+    }
+  }
+
+  // Drain any spare completed loads until no new loads complete on an iteration:
+  unsigned lastNotifications = -1;
+  for( unsigned i = 0; i < MAX_NUM_RESOURCE_TRIES && resourceSink.mGrandTotalCompletions < loadsLaunched && resourceSink.mGrandTotalNotifications != lastNotifications; ++i )
+  {
+    lastNotifications = resourceSink.mGrandTotalNotifications;
+    gAbstraction->GetResources( resourceSink );
+    usleep( 70 * 1000 ); //< 70 ms should allow at least one medium image to load. You  might to increase this to run on a slow device.
+    gAbstraction->GetResources( resourceSink );
+    usleep( 70 * 1000 );
+    gAbstraction->GetResources( resourceSink );
+    usleep( 70 * 1000 );
+    gAbstraction->GetResources( resourceSink );
+  }
+
+  // Check the loads completed as expected:
+
+  tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
+  DALI_TEST_CHECK( loadsLaunched >= resourceSink.mGrandTotalCompletions );
+  DALI_TEST_CHECK( loadsLaunched >= resourceSink.mSuccessCounts.size() );
+  DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
+
+  // Check that if an image was not loaded, it is one of the ones that was cancelled:
+  // This is the main point of this test case.
+  std::vector<Integration::ResourceId> missingLoads;
+  for( unsigned resourceId = 1; resourceId <= NUM_LOAD_GROUPS_TO_ISSUE * NUM_VALID_IMAGES; ++resourceId )
+  {
+    // Was the load (not) completed?
+    if( resourceSink.mCompletionStatuses.find( resourceId ) == resourceSink.mCompletionStatuses.end() )
+    {
+      // Was the load (not) cancelled?
+      if( cancelledLoadSet.find( resourceId ) == cancelledLoadSet.end() )
+      {
+        // Whoa, the load was not completed and not cancelled either... so where did it go then?
+        missingLoads.push_back( resourceId );
+        tet_printf( "Missing load. ResourceId %u was not completed but was also not cancelled.\n", resourceId );
+        ///@note If this fires, you are probably not waiting long enough in the draining loop above (usleep( 70 * 1000 );).
+      }
+    }
+  }
+  DALI_TEST_CHECK( missingLoads.size() == 0U );
+
+  // Check that each success was reported exactly once:
+  for(ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
+  {
+    DALI_TEST_CHECK( it->second == 1u );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp
new file mode 100644 (file)
index 0000000..3d80c50
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "utc-image-loading-common.h"
+
+/** Live platform abstraction recreated for each test case. */
+Integration::PlatformAbstraction * gAbstraction = 0;
+
+/** A variety of parameters to reach different code paths in image loading code. */
+std::vector<ImageParameters> gCancelAttributes;
+
+void utc_dali_loading_startup(void)
+{
+  test_return_value = TET_UNDEF;
+  gAbstraction = CreatePlatformAbstraction();
+
+  // Setup some loading parameters to engage post-processing stages:
+
+  ImageParameters scaleToFillAttributes;
+  scaleToFillAttributes.second.first = FittingMode::SCALE_TO_FILL;
+  scaleToFillAttributes.first = ImageDimensions( 160, 120 );
+  gCancelAttributes.push_back( scaleToFillAttributes );
+
+  // Hit the derived dimensions code:
+  ImageParameters scaleToFillAttributesDeriveWidth = scaleToFillAttributes;
+  scaleToFillAttributesDeriveWidth.first = ImageDimensions( 0, 120 );
+  gCancelAttributes.push_back( scaleToFillAttributesDeriveWidth );
+
+  ImageParameters scaleToFillAttributesDeriveHeight = scaleToFillAttributes;
+  scaleToFillAttributesDeriveHeight.first = ImageDimensions( 160, 0 );
+  gCancelAttributes.push_back( scaleToFillAttributesDeriveHeight );
+
+  // Try to push a tall crop:
+  ImageParameters scaleToFillAttributesTall = scaleToFillAttributes;
+  scaleToFillAttributesTall.first = ImageDimensions( 160, 480 );
+  ImageParameters scaleToFillAttributesTall2 = scaleToFillAttributes;
+  scaleToFillAttributesTall2.first = ImageDimensions( 160, 509 );
+  ImageParameters scaleToFillAttributesTall3 = scaleToFillAttributes;
+  scaleToFillAttributesTall3.first = ImageDimensions( 37, 251 );
+  gCancelAttributes.push_back( scaleToFillAttributesTall );
+  gCancelAttributes.push_back( scaleToFillAttributesTall2 );
+  gCancelAttributes.push_back( scaleToFillAttributesTall3 );
+
+  // Try to push a wide crop:
+  ImageParameters scaleToFillAttributesWide = scaleToFillAttributes;
+  scaleToFillAttributesWide.first = ImageDimensions( 320, 60 );
+  ImageParameters scaleToFillAttributesWide2 = scaleToFillAttributes;
+  scaleToFillAttributesWide2.first = ImageDimensions( 317, 60 );
+  ImageParameters scaleToFillAttributesWide3 = scaleToFillAttributes;
+  scaleToFillAttributesWide3.first = ImageDimensions( 317, 53 );
+  gCancelAttributes.push_back( scaleToFillAttributesWide );
+  gCancelAttributes.push_back( scaleToFillAttributesWide2 );
+  gCancelAttributes.push_back( scaleToFillAttributesWide3 );
+
+  ImageParameters shrinkToFitAttributes = scaleToFillAttributes;
+  shrinkToFitAttributes.second.first = FittingMode::SHRINK_TO_FIT;
+  gCancelAttributes.push_back( shrinkToFitAttributes );
+
+  ImageParameters fitWidthAttributes = scaleToFillAttributes;
+  fitWidthAttributes.second.first = FittingMode::FIT_WIDTH;
+  gCancelAttributes.push_back( fitWidthAttributes );
+
+  ImageParameters fitHeightAttributes = scaleToFillAttributes;
+  fitHeightAttributes.second.first = FittingMode::FIT_HEIGHT;
+  gCancelAttributes.push_back( fitHeightAttributes );
+
+  ///@ToDo: Add attribute variants for all scale modes.
+  ///@ToDo: Add attribute variants for all filter modes.
+
+  // Pad the array to a prime number to mitigate any accidental periodic
+  // patterns in which image file has which attributes applied to its load:
+  srand48( 104729 );
+  const float lastUniques = gCancelAttributes.size() - 0.001f;
+  while( gCancelAttributes.size() < 61u )
+  {
+    gCancelAttributes.push_back( gCancelAttributes[unsigned(drand48() * lastUniques)] );
+  }
+}
+
+void utc_dali_loading_cleanup(void)
+{
+  delete gAbstraction;
+  gAbstraction = 0;
+
+  test_return_value = TET_PASS;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h
new file mode 100644 (file)
index 0000000..9afcf8d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H__
+#define __DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H__
+#include <unistd.h>
+#include <iostream>
+#include <stdlib.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include "tizen-platform-abstraction.h"
+#include "resource-collector.h"
+
+using namespace Dali;
+using namespace Dali::Integration;
+using namespace Dali::Internal::Platform;
+
+namespace
+{
+/**
+ * The number of loads issued in test cases is a multiple of this. The higher it
+ * is, the more the tests stress the system but the longer they take to run.
+ * A value of 1000 is enough to make load tests take tens of seconds each
+ * on desktop. */
+const unsigned NUM_LOAD_GROUPS_TO_ISSUE = 158;
+
+/**
+ * The number of loads to issue when they will be cancelled.
+ * Cancelled loads are cheap so we do a lot.
+ */
+const unsigned NUM_CANCELLED_LOAD_GROUPS_TO_ISSUE = NUM_LOAD_GROUPS_TO_ISSUE * 10;
+
+/** The number of times to ask for resource load status. */
+const unsigned MAX_NUM_RESOURCE_TRIES = 10;
+
+/** The maximum time to wait for loads to complete when the number of expected loads is known. */
+const unsigned MAX_MILLIS_TO_WAIT_FOR_KNOWN_LOADS = 1000 * 60;
+
+/** Images that should load without issue. */
+const char* const VALID_IMAGES[] = {
+  TEST_IMAGE_DIR "/frac.jpg",
+  TEST_IMAGE_DIR "/frac.24.bmp",
+  TEST_IMAGE_DIR "/frac.png",
+  TEST_IMAGE_DIR "/interlaced.gif",
+  TEST_IMAGE_DIR "/pattern.gif"
+};
+const unsigned NUM_VALID_IMAGES = sizeof(VALID_IMAGES) / sizeof(VALID_IMAGES[0]);
+
+///@ToDo: Add valid ktx, ico, and wbmp image examples.
+
+/** Returns elapsed milliseconds. */
+double GetTimeMilliseconds( Integration::PlatformAbstraction& abstraction )
+{
+  unsigned int seconds;
+  unsigned int microseconds;
+  abstraction.GetTimeMicroseconds( seconds, microseconds );
+  double milliseconds = seconds * 1000.0 + microseconds / 1000.0;
+  return milliseconds;
+}
+
+} // anon namespace
+
+/** Live platform abstraction recreated for each test case. */
+extern Integration::PlatformAbstraction * gAbstraction;
+
+/** A variety of parameters to reach different code paths in the image loading. */
+typedef std::pair<ImageDimensions, std::pair<FittingMode::Type, std::pair<SamplingMode::Type, bool> > > ImageParameters;
+extern std::vector<ImageParameters> gCancelAttributes;
+
+
+void utc_dali_loading_startup(void);
+void utc_dali_loading_cleanup(void);
+
+#endif // __DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H__
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-load-completion.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-loading-load-completion.cpp
new file mode 100644 (file)
index 0000000..dc5ecf0
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "utc-image-loading-common.h"
+
+void utc_image_loading_load_completion_startup(void)
+{
+  utc_dali_loading_startup();
+}
+
+void utc_image_loading_load_completion_cleanup(void)
+{
+  utc_dali_loading_cleanup();
+}
+
+// Positive test case for loading. Load lots and be sure it has succeeded.
+int UtcDaliLoadCompletion(void)
+{
+  tet_printf("Running load completion test \n");
+
+  DALI_ASSERT_ALWAYS( gAbstraction != 0 );
+
+  // Start a bunch of loads that should work:
+
+  Dali::Integration::BitmapResourceType bitmapResourceType;
+  Dali::Integration::LoadResourcePriority priority = Dali::Integration::LoadPriorityNormal;
+  unsigned loadsLaunched = 0;
+
+  for( unsigned loadGroup = 0; loadGroup < NUM_LOAD_GROUPS_TO_ISSUE; ++loadGroup )
+  {
+    for( unsigned validImage = 0; validImage < NUM_VALID_IMAGES; ++validImage )
+    {
+      Dali::Integration::ResourceRequest request( loadGroup * NUM_VALID_IMAGES + validImage + 1, bitmapResourceType, VALID_IMAGES[validImage], priority );
+      gAbstraction->LoadResource( request );
+    }
+    loadsLaunched += NUM_VALID_IMAGES;
+  }
+
+  // Drain the completed loads:
+  Dali::Internal::Platform::ResourceCollector resourceSink;
+  gAbstraction->GetResources( resourceSink );
+  usleep( 500 * 1000 );
+  gAbstraction->GetResources( resourceSink );
+
+  const double startDrainTime = GetTimeMilliseconds( *gAbstraction );
+  while( resourceSink.mGrandTotalCompletions < loadsLaunched && GetTimeMilliseconds( *gAbstraction ) - startDrainTime < MAX_MILLIS_TO_WAIT_FOR_KNOWN_LOADS )
+  {
+    usleep( 100 * 40 );
+    gAbstraction->GetResources( resourceSink );
+  }
+
+  // Check the loads completed as expected:
+
+  tet_printf( "Issued Loads: %u, Completed Loads: %u, Successful Loads: %u, Failed Loads: %u \n", loadsLaunched, resourceSink.mGrandTotalCompletions, unsigned(resourceSink.mSuccessCounts.size()), unsigned(resourceSink.mFailureCounts.size()) );
+  DALI_TEST_CHECK( loadsLaunched == resourceSink.mGrandTotalCompletions );
+  DALI_TEST_CHECK( loadsLaunched == resourceSink.mSuccessCounts.size() );
+  DALI_TEST_CHECK( 0 == resourceSink.mFailureCounts.size() );
+
+  // Check that each success was reported exactly once:
+  for( ResourceCounterMap::const_iterator it = resourceSink.mSuccessCounts.begin(), end = resourceSink.mSuccessCounts.end(); it != end; ++it )
+  {
+    DALI_TEST_CHECK( it->second == 1u );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/style/back_top.png b/automated-tests/style/back_top.png
new file mode 100644 (file)
index 0000000..19cbd76
Binary files /dev/null and b/automated-tests/style/back_top.png differ
diff --git a/automated-tests/style/blue.jpg b/automated-tests/style/blue.jpg
new file mode 100644 (file)
index 0000000..d1db8f7
Binary files /dev/null and b/automated-tests/style/blue.jpg differ
diff --git a/automated-tests/style/gray.jpg b/automated-tests/style/gray.jpg
new file mode 100644 (file)
index 0000000..f1acfdb
Binary files /dev/null and b/automated-tests/style/gray.jpg differ
diff --git a/automated-tests/style/jquery.min.js b/automated-tests/style/jquery.min.js
new file mode 100644 (file)
index 0000000..198b3ff
--- /dev/null
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.1 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML="   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};
+f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()
+{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file
diff --git a/automated-tests/style/orange.jpg b/automated-tests/style/orange.jpg
new file mode 100644 (file)
index 0000000..ac4c749
Binary files /dev/null and b/automated-tests/style/orange.jpg differ
diff --git a/automated-tests/style/popup.js b/automated-tests/style/popup.js
new file mode 100644 (file)
index 0000000..5f994f4
--- /dev/null
@@ -0,0 +1,1215 @@
+/**
+ * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com)
+ * 
+ * Dual licensed under the MIT and GPL licenses. 
+ * This basically means you can use this code however you want for
+ * free, but don't claim to have written it yourself!
+ * Donations always accepted: http://www.JavascriptToolbox.com/donate/
+ * 
+ * Please do not link to the .js files on javascripttoolbox.com from
+ * your site. Copy the files locally to your server instead.
+ * 
+ */
+/* ******************************************************************* */
+/*   UTIL FUNCTIONS                                                    */
+/* ******************************************************************* */
+var Util = {'$VERSION':1.06};
+
+// Util functions - these are GLOBAL so they
+// look like built-in functions.
+
+// Determine if an object is an array
+function isArray(o) {
+       return (o!=null && typeof(o)=="object" && typeof(o.length)=="number" && (o.length==0 || defined(o[0])));
+};
+
+// Determine if an object is an Object
+function isObject(o) {
+       return (o!=null && typeof(o)=="object" && defined(o.constructor) && o.constructor==Object && !defined(o.nodeName));
+};
+
+// Determine if a reference is defined
+function defined(o) {
+       return (typeof(o)!="undefined");
+};
+
+// Iterate over an array, object, or list of items and run code against each item
+// Similar functionality to Perl's map() function
+function map(func) {
+       var i,j,o;
+       var results = [];
+       if (typeof(func)=="string") {
+               func = new Function('$_',func);
+       }
+       for (i=1; i<arguments.length; i++) {
+               o = arguments[i];
+               if (isArray(o)) {
+                       for (j=0; j<o.length; j++) {
+                               results[results.length] = func(o[j]);
+                       }
+               }
+               else if (isObject(o)) {
+                       for (j in o) {
+                               results[results.length] = func(o[j]);
+                       }
+               }
+               else {
+                       results[results.length] = func(o);
+               }
+       }
+       return results;
+};
+
+// Set default values in an object if they are undefined
+function setDefaultValues(o,values) {
+       if (!defined(o) || o==null) {
+               o = {};
+       }
+       if (!defined(values) || values==null) {
+               return o;
+       }
+       for (var val in values) {
+               if (!defined(o[val])) {
+                       o[val] = values[val];
+               }
+       }
+       return o;
+};
+
+/* ******************************************************************* */
+/*   DEFAULT OBJECT PROTOTYPE ENHANCEMENTS                             */
+/* ******************************************************************* */
+// These functions add useful functionality to built-in objects
+Array.prototype.contains = function(o) {
+       var i,l;
+       if (!(l = this.length)) { return false; }
+       for (i=0; i<l; i++) {
+               if (o==this[i]) {
+                       return true;
+               }
+       }
+};
+
+/* ******************************************************************* */
+/*   DOM FUNCTIONS                                                     */
+/* ******************************************************************* */
+var DOM = (function() { 
+       var dom = {};
+       
+       // Get a parent tag with a given nodename
+       dom.getParentByTagName = function(o,tagNames) {
+               if(o==null) { return null; }
+               if (isArray(tagNames)) {
+                       tagNames = map("return $_.toUpperCase()",tagNames);
+                       while (o=o.parentNode) {
+                               if (o.nodeName && tagNames.contains(o.nodeName)) {
+                                       return o;
+                               }
+                       }
+               }
+               else {
+                       tagNames = tagNames.toUpperCase();
+                       while (o=o.parentNode) {
+                               if (o.nodeName && tagNames==o.nodeName) {
+                                       return o;
+                               }
+                       }
+               }
+               return null;
+       };
+       
+       // Remove a node from its parent
+       dom.removeNode = function(o) {
+               if (o!=null && o.parentNode && o.parentNode.removeChild) {
+                       // First remove all attributes which are func references, to avoid memory leaks
+                       for (var i in o) {
+                               if (typeof(o[i])=="function") {
+                                       o[i] = null;
+                               }
+                       }
+                       o.parentNode.removeChild(o);
+                       return true;
+               }
+               return false;
+       };
+
+       // Get the outer width in pixels of an object, including borders, padding, and margin
+       dom.getOuterWidth = function(o) {
+               if (defined(o.offsetWidth)) {
+                       return o.offsetWidth;
+               }
+               return null;
+       };
+
+       // Get the outer height in pixels of an object, including borders, padding, and margin
+       dom.getOuterHeight = function(o) {
+               if (defined(o.offsetHeight)) {
+                       return o.offsetHeight;
+               }
+               return null;
+       };
+
+       // Resolve an item, an array of items, or an object of items
+       dom.resolve = function() {
+               var results = new Array();
+               var i,j,o;
+               for (var i=0; i<arguments.length; i++) {
+                       var o = arguments[i];
+                       if (o==null) {
+                               if (arguments.length==1) {
+                                       return null;
+                               }
+                               results[results.length] = null;
+                       }
+                       else if (typeof(o)=='string') {
+                               if (document.getElementById) {
+                                       o = document.getElementById(o);
+                               }
+                               else if (document.all) {
+                                       o = document.all[o];
+                               }
+                               if (arguments.length==1) {
+                                       return o;
+                               }
+                               results[results.length] = o;
+                       }
+                       else if (isArray(o)) {
+                               for (j=0; j<o.length; j++) {
+                                       results[results.length] = o[j];
+                               }
+                       }
+                       else if (isObject(o)) {
+                               for (j in o) {
+                                       results[results.length] = o[j];
+                               }
+                       }
+                       else if (arguments.length==1) {
+                               return o;
+                       }
+                       else {
+                               results[results.length] = o;
+                       }
+         }
+         return results;
+       };
+       dom.$ = dom.resolve;
+       
+       return dom;
+})();
+
+/* ******************************************************************* */
+/*   CSS FUNCTIONS                                                     */
+/* ******************************************************************* */
+var CSS = (function(){
+       var css = {};
+
+       // Convert an RGB string in the form "rgb (255, 255, 255)" to "#ffffff"
+       css.rgb2hex = function(rgbString) {
+               if (typeof(rgbString)!="string" || !defined(rgbString.match)) { return null; }
+               var result = rgbString.match(/^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/);
+               if (result==null) { return rgbString; }
+               var rgb = +result[1] << 16 | +result[2] << 8 | +result[3];
+               var hex = "";
+               var digits = "0123456789abcdef";
+               while(rgb!=0) { 
+                       hex = digits.charAt(rgb&0xf)+hex; 
+                       rgb>>>=4; 
+               } 
+               while(hex.length<6) { hex='0'+hex; }
+               return "#" + hex;
+       };
+
+       // Convert hyphen style names like border-width to camel case like borderWidth
+       css.hyphen2camel = function(property) {
+               if (!defined(property) || property==null) { return null; }
+               if (property.indexOf("-")<0) { return property; }
+               var str = "";
+               var c = null;
+               var l = property.length;
+               for (var i=0; i<l; i++) {
+                       c = property.charAt(i);
+                       str += (c!="-")?c:property.charAt(++i).toUpperCase();
+               }
+               return str;
+       };
+       
+       // Determine if an object or class string contains a given class.
+       css.hasClass = function(obj,className) {
+               if (!defined(obj) || obj==null || !RegExp) { return false; }
+               var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
+               if (typeof(obj)=="string") {
+                       return re.test(obj);
+               }
+               else if (typeof(obj)=="object" && obj.className) {
+                       return re.test(obj.className);
+               }
+               return false;
+       };
+       
+       // Add a class to an object
+       css.addClass = function(obj,className) {
+               if (typeof(obj)!="object" || obj==null || !defined(obj.className)) { return false; }
+               if (obj.className==null || obj.className=='') { 
+                       obj.className = className; 
+                       return true; 
+               }
+               if (css.hasClass(obj,className)) { return true; }
+               obj.className = obj.className + " " + className;
+               return true;
+       };
+       
+       // Remove a class from an object
+       css.removeClass = function(obj,className) {
+               if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; }
+               if (!css.hasClass(obj,className)) { return false; }
+               var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
+               obj.className = obj.className.replace(re,' ');
+               return true;
+       };
+       
+       // Fully replace a class with a new one
+       css.replaceClass = function(obj,className,newClassName) {
+               if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; }
+               css.removeClass(obj,className);
+               css.addClass(obj,newClassName);
+               return true;
+       };
+       
+       // Get the currently-applied style of an object
+       css.getStyle = function(o, property) {
+               if (o==null) { return null; }
+               var val = null;
+               var camelProperty = css.hyphen2camel(property);
+               // Handle "float" property as a special case
+               if (property=="float") {
+                       val = css.getStyle(o,"cssFloat");
+                       if (val==null) { 
+                               val = css.getStyle(o,"styleFloat"); 
+                       }
+               }
+               else if (o.currentStyle && defined(o.currentStyle[camelProperty])) {
+                       val = o.currentStyle[camelProperty];
+               }
+               else if (window.getComputedStyle) {
+                       val = window.getComputedStyle(o,null).getPropertyValue(property);
+               }
+               else if (o.style && defined(o.style[camelProperty])) {
+                       val = o.style[camelProperty];
+               }
+               // For color values, make the value consistent across browsers
+               // Convert rgb() colors back to hex for consistency
+               if (/^\s*rgb\s*\(/.test(val)) {
+                       val = css.rgb2hex(val);
+               }
+               // Lowercase all #hex values
+               if (/^#/.test(val)) {
+                       val = val.toLowerCase();
+               }
+               return val;
+       };
+       css.get = css.getStyle;
+
+       // Set a style on an object
+       css.setStyle = function(o, property, value) {
+               if (o==null || !defined(o.style) || !defined(property) || property==null || !defined(value)) { return false; }
+               if (property=="float") {
+                       o.style["cssFloat"] = value;
+                       o.style["styleFloat"] = value;
+               }
+               else if (property=="opacity") {
+                       o.style['-moz-opacity'] = value;
+                       o.style['-khtml-opacity'] = value;
+                       o.style.opacity = value;
+                       if (defined(o.style.filter)) {
+                               o.style.filter = "alpha(opacity=" + value*100 + ")";
+                       }
+               }
+               else {
+                       o.style[css.hyphen2camel(property)] = value;
+               }
+               return true;
+       };
+       css.set = css.setStyle;
+       
+       // Get a unique ID which doesn't already exist on the page
+       css.uniqueIdNumber=1000;
+       css.createId = function(o) {
+               if (defined(o) && o!=null && defined(o.id) && o.id!=null && o.id!="") { 
+                       return o.id;
+               }
+               var id = null;
+               while (id==null || document.getElementById(id)!=null) {
+                       id = "ID_"+(css.uniqueIdNumber++);
+               }
+               if (defined(o) && o!=null && (!defined(o.id)||o.id=="")) {
+                       o.id = id;
+               }
+               return id;
+       };
+       
+       return css;
+})();
+
+/* ******************************************************************* */
+/*   EVENT FUNCTIONS                                                   */
+/* ******************************************************************* */
+
+var Event = (function(){
+       var ev = {};
+       
+       // Resolve an event using IE's window.event if necessary
+       // --------------------------------------------------------------------
+       ev.resolve = function(e) {
+               if (!defined(e) && defined(window.event)) {
+                       e = window.event;
+               }
+               return e;
+       };
+       
+       // Add an event handler to a function
+       // Note: Don't use 'this' within functions added using this method, since
+       // the attachEvent and addEventListener models differ.
+       // --------------------------------------------------------------------
+       ev.add = function( obj, type, fn, capture ) {
+               if (obj.addEventListener) {
+                       obj.addEventListener( type, fn, capture );
+                       return true;
+               }
+               else if (obj.attachEvent) {
+                       obj.attachEvent( "on"+type, fn );
+                       return true;
+               }
+               return false;
+       };
+
+       // Get the mouse position of an event
+       // --------------------------------------------------------------------
+       // PageX/Y, where they exist, are more reliable than ClientX/Y because 
+       // of some browser bugs in Opera/Safari
+       ev.getMouseX = function(e) {
+               e = ev.resolve(e);
+               if (defined(e.pageX)) {
+                       return e.pageX;
+               }
+               if (defined(e.clientX)) {
+                       return e.clientX+Screen.getScrollLeft();
+               }
+               return null;
+       };
+       ev.getMouseY = function(e) {
+               e = ev.resolve(e);
+               if (defined(e.pageY)) {
+                       return e.pageY;
+               }
+               if (defined(e.clientY)) {
+                       return e.clientY+Screen.getScrollTop();
+               }
+               return null;
+       };
+
+       // Stop the event from bubbling up to parent elements.
+       // Two method names map to the same function
+       // --------------------------------------------------------------------
+       ev.cancelBubble = function(e) {
+               e = ev.resolve(e);
+               if (typeof(e.stopPropagation)=="function") { e.stopPropagation(); } 
+               if (defined(e.cancelBubble)) { e.cancelBubble = true; }
+       };
+       ev.stopPropagation = ev.cancelBubble;
+
+       // Prevent the default handling of the event to occur
+       // --------------------------------------------------------------------
+       ev.preventDefault = function(e) {
+               e = ev.resolve(e);
+               if (typeof(e.preventDefault)=="function") { e.preventDefault(); } 
+               if (defined(e.returnValue)) { e.returnValue = false; }
+       };
+       
+       return ev;
+})();
+
+/* ******************************************************************* */
+/*   SCREEN FUNCTIONS                                                  */
+/* ******************************************************************* */
+var Screen = (function() {
+       var screen = {};
+
+       // Get a reference to the body
+       // --------------------------------------------------------------------
+       screen.getBody = function() {
+               if (document.body) {
+                       return document.body;
+               }
+               if (document.getElementsByTagName) {
+                       var bodies = document.getElementsByTagName("BODY");
+                       if (bodies!=null && bodies.length>0) {
+                               return bodies[0];
+                       }
+               }
+               return null;
+       };
+
+       // Get the amount that the main document has scrolled from top
+       // --------------------------------------------------------------------
+       screen.getScrollTop = function() {
+               if (document.documentElement && defined(document.documentElement.scrollTop) && document.documentElement.scrollTop>0) {
+                       return document.documentElement.scrollTop;
+               }
+               if (document.body && defined(document.body.scrollTop)) {
+                       return document.body.scrollTop;
+               }
+               return null;
+       };
+       
+       // Get the amount that the main document has scrolled from left
+       // --------------------------------------------------------------------
+       screen.getScrollLeft = function() {
+               if (document.documentElement && defined(document.documentElement.scrollLeft) && document.documentElement.scrollLeft>0) {
+                       return document.documentElement.scrollLeft;
+               }
+               if (document.body && defined(document.body.scrollLeft)) {
+                       return document.body.scrollLeft;
+               }
+               return null;
+       };
+       
+       // Util function to default a bad number to 0
+       // --------------------------------------------------------------------
+       screen.zero = function(n) {
+               return (!defined(n) || isNaN(n))?0:n;
+       };
+
+       // Get the width of the entire document
+       // --------------------------------------------------------------------
+       screen.getDocumentWidth = function() {
+               var width = 0;
+               var body = screen.getBody();
+               if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
+                   var rightMargin = parseInt(CSS.get(body,'marginRight'),10) || 0;
+                   var leftMargin = parseInt(CSS.get(body,'marginLeft'), 10) || 0;
+                       width = Math.max(body.offsetWidth + leftMargin + rightMargin, document.documentElement.clientWidth);
+               }
+               else {
+                       width =  Math.max(body.clientWidth, body.scrollWidth);
+               }
+               if (isNaN(width) || width==0) {
+                       width = screen.zero(self.innerWidth);
+               }
+               return width;
+       };
+       
+       // Get the height of the entire document
+       // --------------------------------------------------------------------
+       screen.getDocumentHeight = function() {
+               var body = screen.getBody();
+               var innerHeight = (defined(self.innerHeight)&&!isNaN(self.innerHeight))?self.innerHeight:0;
+               if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
+                   var topMargin = parseInt(CSS.get(body,'marginTop'),10) || 0;
+                   var bottomMargin = parseInt(CSS.get(body,'marginBottom'), 10) || 0;
+                       return Math.max(body.offsetHeight + topMargin + bottomMargin, document.documentElement.clientHeight, document.documentElement.scrollHeight, screen.zero(self.innerHeight));
+               }
+               return Math.max(body.scrollHeight, body.clientHeight, screen.zero(self.innerHeight));
+       };
+       
+       // Get the width of the viewport (viewable area) in the browser window
+       // --------------------------------------------------------------------
+       screen.getViewportWidth = function() {
+               if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
+                       return document.documentElement.clientWidth;
+               }
+               else if (document.compatMode && document.body) {
+                       return document.body.clientWidth;
+               }
+               return screen.zero(self.innerWidth);
+       };
+       
+       // Get the height of the viewport (viewable area) in the browser window
+       // --------------------------------------------------------------------
+       screen.getViewportHeight = function() {
+               if (!window.opera && document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
+                       return document.documentElement.clientHeight;
+               }
+               else if (document.compatMode && !window.opera && document.body) {
+                       return document.body.clientHeight;
+               }
+               return screen.zero(self.innerHeight);
+       };
+
+       return screen;
+})();var Sort = (function(){
+       var sort = {};
+       sort.AlphaNumeric = function(a,b) {
+               if (a==b) { return 0; }
+               if (a<b) { return -1; }
+               return 1;
+       };
+
+       sort.Default = sort.AlphaNumeric;
+       
+       sort.NumericConversion = function(val) {
+               if (typeof(val)!="number") {
+                       if (typeof(val)=="string") {
+                               val = parseFloat(val.replace(/,/g,''));
+                               if (isNaN(val) || val==null) { val=0; }
+                       }
+                       else {
+                               val = 0;
+                       }
+               }
+               return val;
+       };
+       
+       sort.Numeric = function(a,b) {
+               return sort.NumericConversion(a)-sort.NumericConversion(b);
+       };
+
+       sort.IgnoreCaseConversion = function(val) {
+               if (val==null) { val=""; }
+               return (""+val).toLowerCase();
+       };
+
+       sort.IgnoreCase = function(a,b) {
+               return sort.AlphaNumeric(sort.IgnoreCaseConversion(a),sort.IgnoreCaseConversion(b));
+       };
+
+       sort.CurrencyConversion = function(val) {
+               if (typeof(val)=="string") {
+                       val = val.replace(/^[^\d\.]/,'');
+               }
+               return sort.NumericConversion(val);
+       };
+       
+       sort.Currency = function(a,b) {
+               return sort.Numeric(sort.CurrencyConversion(a),sort.CurrencyConversion(b));
+       };
+       
+       sort.DateConversion = function(val) {
+               // inner util function to parse date formats
+               function getdate(str) {
+                       // inner util function to convert 2-digit years to 4
+                       function fixYear(yr) {
+                               yr = +yr;
+                               if (yr<50) { yr += 2000; }
+                               else if (yr<100) { yr += 1900; }
+                               return yr;
+                       };
+                       var ret;
+                       // YYYY-MM-DD
+                       if (ret=str.match(/(\d{2,4})-(\d{1,2})-(\d{1,2})/)) {
+                               return (fixYear(ret[1])*10000) + (ret[2]*100) + (+ret[3]);
+                       }
+                       // MM/DD/YY[YY] or MM-DD-YY[YY]
+                       if (ret=str.match(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})/)) {
+                               return (fixYear(ret[3])*10000) + (ret[1]*100) + (+ret[2]);
+                       }
+                       return 99999999; // So non-parsed dates will be last, not first
+               };
+               return getdate(val);
+       };
+
+       sort.Date = function(a,b) {
+               return sort.Numeric(sort.DateConversion(a),sort.DateConversion(b));
+       };
+
+       return sort;
+})();
+
+var Position = (function() {
+       // Resolve a string identifier to an object
+       // ========================================
+       function resolveObject(s) {
+               if (document.getElementById && document.getElementById(s)!=null) {
+                       return document.getElementById(s);
+               }
+               else if (document.all && document.all[s]!=null) {
+                       return document.all[s];
+               }
+               else if (document.anchors && document.anchors.length && document.anchors.length>0 && document.anchors[0].x) {
+                       for (var i=0; i<document.anchors.length; i++) {
+                               if (document.anchors[i].name==s) { 
+                                       return document.anchors[i]
+                               }
+                       }
+               }
+       }
+       
+       var pos = {};
+       pos.$VERSION = 1.0;
+       
+       // Set the position of an object
+       // =============================
+       pos.set = function(o,left,top) {
+               if (typeof(o)=="string") {
+                       o = resolveObject(o);
+               }
+               if (o==null || !o.style) {
+                       return false;
+               }
+               
+               // If the second parameter is an object, it is assumed to be the result of getPosition()
+               if (typeof(left)=="object") {
+                       var pos = left;
+                       left = pos.left;
+                       top = pos.top;
+               }
+               
+               o.style.left = left + "px";
+               o.style.top = top + "px";
+               return true;
+       };
+       
+       // Retrieve the position and size of an object
+       // ===========================================
+       pos.get = function(o) {
+               var fixBrowserQuirks = true;
+                       // If a string is passed in instead of an object ref, resolve it
+               if (typeof(o)=="string") {
+                       o = resolveObject(o);
+               }
+               
+               if (o==null) {
+                       return null;
+               }
+               
+               var left = 0;
+               var top = 0;
+               var width = 0;
+               var height = 0;
+               var parentNode = null;
+               var offsetParent = null;
+       
+               
+               offsetParent = o.offsetParent;
+               var originalObject = o;
+               var el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
+               while (el.parentNode!=null) {
+                       el = el.parentNode;
+                       if (el.offsetParent==null) {
+                       }
+                       else {
+                               var considerScroll = true;
+                               /*
+                               In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already 
+                               take its scroll position into account. If elements further up the chain are scrollable, their 
+                               scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
+                               which must be ignored.
+                               */
+                               if (fixBrowserQuirks && window.opera) {
+                                       if (el==originalObject.parentNode || el.nodeName=="TR") {
+                                               considerScroll = false;
+                                       }
+                               }
+                               if (considerScroll) {
+                                       if (el.scrollTop && el.scrollTop>0) {
+                                               top -= el.scrollTop;
+                                       }
+                                       if (el.scrollLeft && el.scrollLeft>0) {
+                                               left -= el.scrollLeft;
+                                       }
+                               }
+                       }
+                       // If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
+                       if (el == offsetParent) {
+                               left += o.offsetLeft;
+                               if (el.clientLeft && el.nodeName!="TABLE") { 
+                                       left += el.clientLeft;
+                               }
+                               top += o.offsetTop;
+                               if (el.clientTop && el.nodeName!="TABLE") {
+                                       top += el.clientTop;
+                               }
+                               o = el;
+                               if (o.offsetParent==null) {
+                                       if (o.offsetLeft) {
+                                               left += o.offsetLeft;
+                                       }
+                                       if (o.offsetTop) {
+                                               top += o.offsetTop;
+                                       }
+                               }
+                               offsetParent = o.offsetParent;
+                       }
+               }
+               
+       
+               if (originalObject.offsetWidth) {
+                       width = originalObject.offsetWidth;
+               }
+               if (originalObject.offsetHeight) {
+                       height = originalObject.offsetHeight;
+               }
+               
+               return {'left':left, 'top':top, 'width':width, 'height':height
+                               };
+       };
+       
+       // Retrieve the position of an object's center point
+       // =================================================
+       pos.getCenter = function(o) {
+               var c = this.get(o);
+               if (c==null) { return null; }
+               c.left = c.left + (c.width/2);
+               c.top = c.top + (c.height/2);
+               return c;
+       };
+       
+       return pos;
+})();// CLASS CONSTRUCTOR
+// --------------------------------------------------------------------
+var Popup = function(div, options) {
+       this.div = defined(div)?div:null;
+       this.index = Popup.maxIndex++;
+       this.ref = "Popup.objects["+this.index+"]";
+       Popup.objects[this.index] = this;
+       // Store a reference to the DIV by id, also
+       if (typeof(this.div)=="string") {
+               Popup.objectsById[this.div] = this;
+       }
+       if (defined(this.div) && this.div!=null && defined(this.div.id)) {
+               Popup.objectsById[this.div.id] = this.div.id;
+       }
+       // Apply passed-in options
+       if (defined(options) && options!=null && typeof(options)=="object") {
+               for (var i in options) {
+                       this[i] = options[i];
+               }
+       }
+       return this;
+};
+
+// CLASS PROPERTIES
+// --------------------------------------------------------------------
+// Index of popup objects, to maintain a global reference if necessary
+Popup.maxIndex = 0;
+Popup.objects = {};
+Popup.objectsById = {};
+
+// The z-index value that popups will start at
+Popup.minZIndex = 101;
+
+// Class names to assign to other objects
+Popup.screenClass = "PopupScreen";
+Popup.iframeClass = "PopupIframe";
+Popup.screenIframeClass = "PopupScreenIframe";
+
+// CLASS METHODS
+// --------------------------------------------------------------------
+
+// Hide all currently-visible non-modal dialogs
+Popup.hideAll = function() {
+       for (var i in Popup.objects) {
+               var p = Popup.objects[i];
+               if (!p.modal && p.autoHide) {
+                       p.hide();
+               }
+       }
+};
+// Catch global events as a trigger to hide auto-hide popups
+Event.add(document, "mouseup", Popup.hideAll, false);
+
+// A simple class method to show a popup without creating an instance
+Popup.show = function(divObject, referenceObject, position, options, modal) {
+       var popup;
+       if (defined(divObject)) { 
+               popup = new Popup(divObject);
+       }
+       else {
+               popup = new Popup();
+               popup.destroyDivOnHide = true;
+       }
+       if (defined(referenceObject)) { popup.reference = DOM.resolve(referenceObject); }
+       if (defined(position)) { popup.position = position; }
+       if (defined(options) && options!=null && typeof(options)=="object") {
+               for (var i in options) {
+                       popup[i] = options[i];
+               }
+       }
+       if (typeof(modal)=="boolean") {
+               popup.modal = modal;
+       }
+       popup.destroyObjectsOnHide = true;
+       popup.show();
+       return popup;
+};
+
+// A simple class method to show a modal popup
+Popup.showModal = function(divObject, referenceObject, position, options) {
+       Popup.show(divObject, referenceObject, position, options, true);
+};
+
+// A method to retrieve a popup object based on a div ID
+Popup.get = function(divId) {
+       if (defined(Popup.objectsById[divId])) {
+               return Popup.objectsById[divId];
+       }
+       return null;
+};
+
+// A method to hide a popup based on a div id
+Popup.hide = function(divId) {
+       var popup = Popup.get(divId);
+       if (popup!=null) {
+               popup.hide();
+       }
+};
+
+// PROTOTYPE PROPERTIES
+// --------------------------------------------------------------------
+Popup.prototype.content = null;
+Popup.prototype.className = "PopupDiv";
+Popup.prototype.style = null; // Styles to be applied to the DIV
+Popup.prototype.width = null;
+Popup.prototype.height = null;
+Popup.prototype.top = null;
+Popup.prototype.left = null;
+Popup.prototype.offsetLeft = 0;
+Popup.prototype.offsetTop = 0;
+Popup.prototype.constrainToScreen = true;
+Popup.prototype.autoHide = true;
+Popup.prototype.useIframeShim = false; /*@cc_on @*/ /*@if (@_win32) {Popup.prototype.useIframeShim = true;} @end @*/ 
+Popup.prototype.iframe = null;
+Popup.prototype.position = null; // vertical: "above top center bottom below", horizontal: "adjacent-left,left,center,right,adjacent-right"
+Popup.prototype.reference = null;
+Popup.prototype.modal = false;
+Popup.prototype.destroyDivOnHide = false;
+Popup.prototype.destroyObjectsOnHide = false;
+Popup.prototype.screen = null;
+Popup.prototype.screenIframeShim = null;
+Popup.prototype.screenOpacity=.4;
+Popup.prototype.screenColor="#cccccc";
+
+// INSTANCE METHODS
+// --------------------------------------------------------------------
+
+// Show the popup
+// --------------------------------------------------------------------
+Popup.prototype.show = function(options, modal) {
+       this.modal = this.modal || (typeof(modal)=="boolean" && modal);
+       if (defined(options) && options!=null && typeof(options)=="object") {
+               for (var i in options) {
+                       this[i] = options[i];
+               }
+       }
+       this.div = DOM.resolve(this.div);
+       CSS.setStyle(this.div,'position','absolute');
+       
+       // If there is no div pre-defined to use, create one
+       if (this.div==null) {
+               this.div = this.createDiv();
+       }
+       if (this.content!=null) {
+               this.div.innerHTML = this.content;
+               this.content = null;
+       }
+       if (this.className!=null) {
+               this.div.className = this.className;
+       }
+       if (this.style!=null) {
+               this.applyStyle();
+       }
+       if (this.width!=null) {
+               this.div.style.width = this.width+"px";
+               this.div.style.overflowX="auto";
+       }
+       if (this.height!=null) {
+               this.div.style.height = this.height+"px";
+               this.div.style.overflowY="auto";
+       }
+
+       // Do the actual display - this is a separate method so display transitions can be implemented
+       this.transition();
+       
+       // Make sure clicks on the DIV don't bubble up to the document
+       this.div.onclick = function(e) { 
+               Event.cancelBubble(Event.resolve(e));
+       };
+       this.div.onmouseup = this.div.onclick;
+       
+       // Focus to the DIV if possible 
+       if (this.modal && this.div.focus) {
+               this.div.focus();
+       }
+};
+
+// Show the popup but make it modal
+// --------------------------------------------------------------------
+Popup.prototype.transition = function() {
+       if (this.modal) {
+               this.addScreen();
+       }
+       
+       // Make the DIV displayed but hidden so its size can be measured
+       CSS.setStyle(this.div,'visibility','hidden');
+       CSS.setStyle(this.div,'display','block');
+
+       // Position the popup
+       this.setPosition();
+
+       // Add the shim if necessary    
+       if (this.useIframeShim) {
+               this.addIframeShim();
+       }
+
+       // Make sure the DIV is higher than the shim
+       this.div.style.zIndex = Popup.minZIndex++;
+
+       CSS.setStyle(this.div,'display','block');
+       CSS.setStyle(this.div,'visibility','visible');
+};
+
+// Show the popup but make it modal
+// --------------------------------------------------------------------
+Popup.prototype.showModal = function(options) {
+       this.show(options,true);
+};
+
+// Apply user styles to the DIV
+// --------------------------------------------------------------------
+Popup.prototype.applyStyle = function() {
+       if (this.div!=null && this.style!=null && typeof(this.style)=="object") {
+               for (var i in this.style) {
+                       this.div.style[i] = this.style[i];
+               }
+       }
+};
+
+// Hide the popup
+// --------------------------------------------------------------------
+Popup.prototype.hide = function() {
+       // If this was a temp object creating on-the-fly, then remove objects from the DOM so
+       // The document doesn't get littered with extra objects
+       if (this.destroyDivOnHide) {
+               DOM.removeNode(this.div);
+               this.div = null;
+               delete Popup.objects[this.id];
+       }
+       else if (this.div!=null) {
+               CSS.setStyle(this.div,'display','none');
+       }
+
+       if (this.destroyObjectsOnHide) {
+               DOM.removeNode(this.iframe);
+               DOM.removeNode(this.screen);
+               DOM.removeNode(this.screenIframeShim);
+       }
+       else {
+               if (this.iframe!=null) {
+                       this.iframe.style.display = "none";
+               }
+               if (this.screen!=null) {
+                       this.screen.style.display = "none";
+               }
+               if (this.screenIframeShim!=null) {
+                       this.screenIframeShim.style.display = "none";
+               }
+       }
+};
+
+// Util funcs for position
+// --------------------------------------------------------------------
+Popup.prototype.setTop = function(top) {
+       this.div.style.top = top+"px";
+};
+Popup.prototype.setLeft = function(left) {
+       this.div.style.left = left+"px";
+};
+Popup.prototype.getTop = function() {
+       return parseInt(CSS.getStyle(this.div,"top"),10);
+};
+Popup.prototype.getLeft = function() {
+       return parseInt(CSS.getStyle(this.div,"left"),10);
+};
+
+// All the logic to position the popup based on various criteria
+// --------------------------------------------------------------------
+Popup.prototype.setPosition = function() {
+       if (this.position!=null) {
+               var m = this.position.match(/^(\S+)\s+(\S+)/); 
+               if (m!=null && m.length==3) {
+                       var v = m[1];
+                       var h = m[2];
+
+                       var ref = this.reference;
+                       if (ref==null) { ref = Screen.getBody(); }
+                       var p = Position.get(ref);
+                       var refTop = p.top;
+                       var refLeft = p.left;
+                       var refWidth = DOM.getOuterWidth(ref);
+                       var refHeight = DOM.getOuterHeight(ref);
+                       
+                       var width = DOM.getOuterWidth(this.div);
+                       var height = DOM.getOuterHeight(this.div);
+                       
+                       var scrollLeft = Screen.getScrollLeft();
+                       var scrollTop = Screen.getScrollTop();
+
+                       // Set vertical position relative to reference object
+                       if (v=="above") { this.setTop(refTop-height+this.offsetTop); }
+                       else if (v=="top") { this.setTop(refTop+this.offsetTop); }
+                       else if (v=="center") { this.setTop(refTop+(refHeight/2)-(height/2)+this.offsetTop); }
+                       else if (v=="bottom") { this.setTop(refTop+refHeight-height+this.offsetTop); }
+                       else if (v=="below") { this.setTop(refTop+refHeight+this.offsetTop); }
+
+                       // Set horizontal position relative to reference object
+                       if (h=="adjacent-left") { this.setLeft(refLeft-width+this.offsetLeft); }
+                       else if (h=="left") { this.setLeft(refLeft+this.offsetLeft); }
+                       else if (h=="center") { this.setLeft(refLeft+(refWidth/2)-(width/2)+this.offsetLeft); }
+                       else if (h=="right") { this.setLeft(refLeft+refWidth-width+this.offsetLeft); }
+                       else if (h=="adjacent-right") { this.setLeft(refLeft+refWidth+this.offsetLeft); }
+               }
+       }
+       else if (this.top==null && this.left==null) {
+               this.center();
+       }
+       else {
+               if (this.top==null) { this.top=0; }
+               if (this.left==null) { this.left=0; }
+               this.div.style.top = this.top+this.offsetTop+"px";
+               this.div.style.left = this.left+this.offsetLeft+"px";
+       }
+
+       // Re-position to make sure it stays on the screen
+       if (this.constrainToScreen) {
+               this.fitToScreen();
+       }
+};
+
+// Append an object to the body
+// --------------------------------------------------------------------
+Popup.prototype.appendToBody = function(o) {
+       var body = Screen.getBody();
+       if (body && body.appendChild) {
+               body.appendChild(o);
+       }
+};
+
+// Create a new DIV object to be used for a popup
+// --------------------------------------------------------------------
+Popup.prototype.createDiv = function() {
+       if (document.createElement) {
+               var d = document.createElement("DIV");
+               d.style.position="absolute";
+               d.style.display="block";
+               d.style.visibility="hidden";
+               this.appendToBody(d);
+               return d;
+       }
+       alert("ERROR: Couldn't create DIV element in Popup.prototype.createDiv()");
+       return null;
+};
+
+// Create a new IFRAME object to be used behind the popup
+// --------------------------------------------------------------------
+Popup.prototype.createIframe = function() {
+       if (document.createElement) {
+               var i= document.createElement("IFRAME");
+               i.style.position="absolute";
+               i.style.display="block";
+               i.style.visibility="hidden";
+               i.style.background="none";
+               this.appendToBody(i);
+               return i;
+       }
+       else {
+               alert("ERROR: Couldn't create IFRAME object in Popup.prototype.createIframe()");
+       }
+};
+
+// Add an IFRAME shim for the DIV
+// --------------------------------------------------------------------
+Popup.prototype.addIframeShim = function() {
+       if (this.iframe==null) {
+               this.iframe = this.createIframe();
+       }
+       this.iframe.className = Popup.iframeClass;
+       CSS.setStyle(this.iframe,'top',this.getTop()+"px");
+       CSS.setStyle(this.iframe,'left',this.getLeft()+"px");
+       CSS.setStyle(this.iframe,'width',DOM.getOuterWidth(this.div) + "px");
+       CSS.setStyle(this.iframe,'height',DOM.getOuterHeight(this.div) + "px");
+       CSS.setStyle(this.iframe,'zIndex',Popup.minZIndex++);
+       CSS.setStyle(this.iframe,'opacity',0);
+       CSS.setStyle(this.iframe,'visibility','visible');
+       CSS.setStyle(this.iframe,'display','block');
+};
+
+// Create a "screen" to make a popup modal
+// --------------------------------------------------------------------
+Popup.prototype.addScreen = function() {
+       if (this.screen==null) {
+               this.screen = this.createDiv();
+               this.screen.style.top="0px";
+               this.screen.style.left="0px";
+               this.screen.style.backgroundColor = this.screenColor;
+               this.screen.className=Popup.screenClass;;
+               CSS.setStyle(this.screen,"opacity",this.screenOpacity);
+               this.screen.onclick = function(e) { Event.cancelBubble(Event.resolve(e)); }
+       }
+       if (this.screenIframeShim==null) {
+               this.screenIframeShim = this.createIframe();
+               this.screenIframeShim.style.top="0px";
+               this.screenIframeShim.style.left="0px";
+               this.screenIframeShim.className=Popup.screenIframeClass;
+               CSS.setStyle(this.screenIframeShim,"opacity",0);
+       }
+       this.screen.style.width = Screen.getDocumentWidth()+"px";
+       this.screen.style.height = Screen.getDocumentHeight()+"px";
+       this.screenIframeShim.style.width = Screen.getDocumentWidth()+"px";
+       this.screenIframeShim.style.height = Screen.getDocumentHeight()+"px";
+       this.screenIframeShim.style.zIndex = Popup.minZIndex++;
+       this.screenIframeShim.style.visibility="visible";
+       this.screenIframeShim.style.display="block";
+       this.screen.style.zIndex = Popup.minZIndex++;
+       this.screen.style.visibility="visible";
+       this.screen.style.display="block";
+};
+
+// Re-position the DIV so it stays on the screen
+// --------------------------------------------------------------------
+Popup.prototype.fitToScreen = function() {
+       var width = DOM.getOuterWidth(this.div);
+       var height = DOM.getOuterHeight(this.div);
+       var top = this.getTop();
+       var left = this.getLeft();
+       
+       var clientWidth = Screen.getViewportWidth();
+       var clientHeight = Screen.getViewportHeight();
+       
+       var scrollLeft = Screen.getScrollLeft();
+       var scrollTop = Screen.getScrollTop();
+
+       if (top-scrollTop+height>clientHeight) {
+               top = top - ((top+height) - (scrollTop+clientHeight));
+               this.div.style.top = top + "px";
+       }
+       if (left-scrollLeft+width>clientWidth) {
+               left = left - ((left+width) - (scrollLeft+clientWidth));
+               this.div.style.left = left + "px";
+       }
+       if (top<scrollTop) {
+               this.div.style.top=scrollTop+"px";
+       }
+       if (left<scrollLeft) {
+               this.div.style.left=scrollLeft+"px";
+       }
+};
+
+// Center the DIV object
+// --------------------------------------------------------------------
+Popup.prototype.center = function() {
+       var left = DOM.getOuterWidth(this.div);
+       var top = DOM.getOuterHeight(this.div);
+       if (isNaN(left)) { left=0; }
+       if (isNaN(top)) { top=0; }      
+       var clientW = Screen.getViewportWidth();
+       var clientH = Screen.getViewportHeight();
+       if (clientW!=null && clientH!=null) {
+               top = (clientH-top)/2;
+               left = (clientW-left)/2;
+       }
+       top += Screen.getScrollTop();
+       left += Screen.getScrollLeft();
+       
+       this.div.style.top = top+this.offsetTop+"px";
+       this.div.style.left = left+this.offsetLeft+"px";
+};
+
diff --git a/automated-tests/style/red.jpg b/automated-tests/style/red.jpg
new file mode 100644 (file)
index 0000000..ab67c5a
Binary files /dev/null and b/automated-tests/style/red.jpg differ
diff --git a/automated-tests/style/summary.xsl b/automated-tests/style/summary.xsl
new file mode 100644 (file)
index 0000000..c034df8
--- /dev/null
@@ -0,0 +1,352 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+       <xsl:output method="html" version="1.0" encoding="UTF-8"
+               indent="yes" />
+       <xsl:template match="/">
+               <html>
+                       <STYLE type="text/css">
+                               @import "./style/tests.css";
+                       </STYLE>
+                       <head>
+                               <script type="text/javascript" src="./style/jquery.min.js" />
+                       </head>
+                       <body>
+                               <div id="testcasepage">
+                                       <div id="title">
+                                               <table>
+                                                       <tr>
+                                                               <td>
+                                                                       <h1>TCT Report</h1>
+                                                               </td>
+                                                       </tr>
+                                               </table>
+                                       </div>
+                                       <div id="overview">
+                                       <table>
+                                               <tr>
+                                                       <td>
+                                       <div id="summary">
+                                               <table>
+                                                       <tr>
+                                                               <th colspan="2">Test Summary</th>
+                                                       </tr>
+                                                       <!-- tr>
+                                                               <td>TCT Version</td>
+                                                               <td>
+                                                                       <xsl:value-of select="result_summary/environment/@cts_version" />
+                                                               </td>
+                                                       </tr -->
+                                                       <tr>
+                                                               <td>Test Plan Name</td>
+                                                               <td>
+                                                                       <xsl:value-of select="result_summary/@plan_name" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Build ID</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@build_id">
+                                                                                       <xsl:if test="result_summary/environment/@build_id = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@build_id" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Test Total</td>
+                                                               <td>
+                                                                       <xsl:value-of select="sum(result_summary//suite/total_case)" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Test Passed</td>
+                                                               <td>
+                                                                       <xsl:value-of select="sum(result_summary//suite/pass_case)" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Test Failed</td>
+                                                               <td>
+                                                                       <xsl:value-of select="sum(result_summary//suite/fail_case)" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Test Blocked</td>
+                                                               <td>
+                                                                       <xsl:value-of select="sum(result_summary//suite/block_case)" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Test Not Executed</td>
+                                                               <td>
+                                                                       <xsl:value-of select="sum(result_summary//suite/na_case)" />
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Time</td>
+                                                               <td>
+                                                                       <xsl:value-of select="result_summary/summary/start_at" />
+                                                                       ~
+                                                                       <xsl:value-of select="result_summary/summary/end_at" />
+                                                               </td>
+                                                       </tr>
+                                               </table>
+                                       </div>
+                                       </td>
+                                       <td>
+                                       <div id="device">
+                                               <table>
+                                                       <tr>
+                                                               <th colspan="2">Device Information</th>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Host Device</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@host">
+                                                                                       <xsl:if test="result_summary/environment/@host = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@host" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Manufacturer</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@manufacturer">
+                                                                                       <xsl:if test="result_summary/environment/@manufacturer = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@manufacturer" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Device Model</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@device_model">
+                                                                                       <xsl:if test="result_summary/environment/@device_model = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@device_model" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Device ID</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@device_id">
+                                                                                       <xsl:if test="result_summary/environment/@device_id = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@device_id" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Screen Size</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@screen_size">
+                                                                                       <xsl:if test="result_summary/environment/@screen_size = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@screen_size" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                                       <tr>
+                                                               <td>Resolution</td>
+                                                               <td>
+                                                                       <xsl:choose>
+                                                                               <xsl:when test="result_summary/environment/@resolution">
+                                                                                       <xsl:if test="result_summary/environment/@resolution = ''">
+                                                                                               N/A
+                                                                                       </xsl:if>
+                                                                                       <xsl:value-of select="result_summary/environment/@resolution" />
+                                                                               </xsl:when>
+                                                                               <xsl:otherwise>
+                                                                                       N/A
+                                                                               </xsl:otherwise>
+                                                                       </xsl:choose>
+                                                               </td>
+                                                       </tr>
+                                               </table>
+                                       </div>
+                                       </td>
+                                       </tr>
+                                       </table>
+                                       </div>
+
+                                       <div id="capability">
+                                               <div id="title">
+                                                       <a name="contents"></a>
+                                                       <table>
+                                                               <tr>
+                                                                       <td class="title">
+                                                                               <h1><a href="#" class="see_capabilities">Device Capability</a></h1>
+                                                                       </td>
+                                                               </tr>
+                                                       </table>
+                                               </div>
+                                               <xsl:choose>
+                                                       <xsl:when test="result_summary/capabilities">
+                                                               <div id="capability_table" style="display:none;">
+                                                               <table>
+                                                                       <tr>
+                                                                               <th>Capability Name</th>
+                                                                               <th>Type</th>
+                                                                               <th>Value</th>
+                                                                       </tr>
+                                                                       <xsl:for-each select="result_summary/capabilities/capability">
+                                                                               <xsl:sort select="@name" />
+                                                                               <tr>
+                                                                                       <td>
+                                                                                               <xsl:value-of select="@name" />
+                                                                                       </td>
+                                                                                       <td>
+                                                                                               <xsl:value-of select="@type" />
+                                                                                       </td>
+                                                                                       <td>
+                                                                                               <xsl:choose>
+                                                                                                       <xsl:when test="value">
+                                                                                                               <xsl:value-of select="value" />
+                                                                                                       </xsl:when>
+                                                                                                       <xsl:otherwise>
+                                                                                                               <xsl:value-of select="@support" />
+                                                                                                       </xsl:otherwise>
+                                                                                               </xsl:choose>
+                                                                                       </td>
+                                                                               </tr>
+                                                                       </xsl:for-each>
+                                                               </table>
+                                                               </div>
+                                                       </xsl:when>
+                                                       <xsl:otherwise>
+                                                               The information of device capability is not available.
+                                                       </xsl:otherwise>
+                                               </xsl:choose>
+                                       </div>
+
+                                       <div id="suite_summary">
+                                               <div id="title">
+                                                       <a name="contents"></a>
+                                                       <table>
+                                                               <tr>
+                                                                       <td class="title">
+                                                                               <h1>Test Summary by Suite</h1>
+                                                                       </td>
+                                                               </tr>
+                                                       </table>
+                                               </div>
+                                               <table>
+                                                       <tr>
+                                                               <th>Suite</th>
+                                                               <th>Total</th>
+                                                               <th>Passed</th>
+                                                               <th>Failed</th>
+                                                               <th>Blocked</th>
+                                                               <th>Not Executed</th>
+                                                               <th class="Ratio">Ratio</th>
+                                                       </tr>
+                                                       <xsl:for-each select="result_summary/suite">
+                                                               <xsl:sort select="@name" />
+                                                               <tr class="suite_item">
+                                                                       <xsl:attribute name="id">
+                                                <xsl:value-of
+                                                                               select="@name" />
+                                    </xsl:attribute>
+                                                                       <td>
+                                                                               <a>
+                                                                                       <xsl:attribute name="href"><xsl:value-of
+                                                                                               select="@name" />.xml</xsl:attribute>
+                                                                                       <xsl:value-of select="@name" />
+                                                                               </a>
+                                                                       </td>
+                                                                       <td class="total">
+                                                                               <xsl:value-of select="total_case" />
+                                                                       </td>
+                                                                       <td class="pass">
+                                                                               <xsl:value-of select="pass_case" />
+                                                                       </td>
+                                                                       <td class="fail">
+                                                                               <xsl:value-of select="fail_case" />
+                                                                       </td>
+                                                                       <td class="block">
+                                                                               <xsl:value-of select="block_case" />
+                                                                       </td>
+                                                                       <td class="na">
+                                                                               <xsl:value-of select="na_case" />
+                                                                       </td>
+                                                                       <td class="Ratio">
+                                                                               <div class="RatioGraphic" />
+                                                                       </td>
+                                                               </tr>
+                                                       </xsl:for-each>
+                                               </table>
+                                       </div>
+
+                               </div>
+                               <div id="goTopBtn">
+                                       <img border="0" src="./style/back_top.png" />
+                               </div>
+                               <script type="text/javascript" src="./style/application.js" />
+                               <script language="javascript" type="text/javascript">
+                                       $(document).ready(function(){
+                                       goTopEx();
+                                       drawRatio();
+                                       });
+                               </script>
+                       </body>
+               </html>
+       </xsl:template>
+       <xsl:template name="br-replace">
+               <xsl:param name="word" />
+               <xsl:variable name="cr">
+                       <xsl:text>\n</xsl:text>
+               </xsl:variable>
+               <xsl:choose>
+                       <xsl:when test="contains($word,$cr)">
+                               <xsl:value-of select="substring-before($word,$cr)" />
+                               <br />
+                               <xsl:call-template name="br-replace">
+                                       <xsl:with-param name="word" select="substring-after($word,$cr)" />
+                               </xsl:call-template>
+                       </xsl:when>
+                       <xsl:otherwise>
+                               <xsl:value-of select="$word" />
+                       </xsl:otherwise>
+               </xsl:choose>
+       </xsl:template>
+</xsl:stylesheet>
diff --git a/automated-tests/style/testresult.xsl b/automated-tests/style/testresult.xsl
new file mode 100644 (file)
index 0000000..019b445
--- /dev/null
@@ -0,0 +1,571 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0"
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+       <xsl:output method="html" version="1.0" encoding="UTF-8"
+               indent="yes" />
+       <xsl:template match="/">
+               <html>
+                       <STYLE type="text/css">
+                               @import "./style/tests.css";
+                       </STYLE>
+                       <head>
+                               <script type="text/javascript" src="./style/jquery.min.js" />
+                               <script type="text/javascript" src="./style/popup.js" />
+                       </head>
+                       <body>
+                               <div id="title">
+                                       <table>
+                                               <tr>
+                                                       <td class="title">
+                                                               <h1 align="center">Suite Test Results</h1>
+                                                       </td>
+                                               </tr>
+                                       </table>
+                               </div>
+                               <div id="btc">
+                                       <table>
+                                               <tr>
+                                                       <td>
+                                                               <a href="#" class="see_all">Show all</a>
+                                                       </td>
+                                                       <td>
+                                                               <a href="#" class="see_failed">Show only failed</a>
+                                                       </td>
+                                                       <td>
+                                                               <a href="#" class="see_blocked">Show only blocked</a>
+                                                       </td>
+                                                       <td>
+                                                               <a href="#" class="see_na">Show only not executed</a>
+                                                       </td>
+                                                       <td>
+                                                               <a href="summary.xml">Summary</a>
+                                                       </td>
+                                               </tr>
+                                       </table>
+                               </div>
+                               <div id="testcasepage">
+                                       <div id="cases">
+                                               <div id="see_all">
+                                                       <xsl:for-each select="test_definition/suite">
+                                                               <xsl:sort select="@name" />
+                                                               <div id="suite_title">
+                                                                       <h2>
+                                                                               Test Suite:
+                                                                               <xsl:value-of select="@name" />
+                                                                               (All)
+                                                                       </h2>
+                                                                       <a>
+                                                                               <xsl:attribute name="name">
+                                                                     <xsl:value-of
+                                                                                       select="@name" />
+                                                                  </xsl:attribute>
+                                                                       </a>
+                                                               </div>
+                                                               <table>
+                                                                       <tr>
+                                                                               <th>Case_ID</th>
+                                                                               <th>Purpose</th>
+                                                                               <th>Result</th>
+                                                                               <th>Stderr</th>
+                                                                       </tr>
+                                                                       <xsl:for-each select=".//set">
+                                                                               <xsl:sort select="@name" />
+                                                                               <tr>
+                                                                                       <xsl:choose>
+                                                                                               <xsl:when test="@name">
+                                                                                                       <td colspan="3">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                                       <td colspan="1">
+                                                                                                               <h4>
+                                                                                                                       <a>
+                                                                                                                               <xsl:attribute name="href"><xsl:value-of
+                                                                                                                                       select="@set_debug_msg" /></xsl:attribute>
+                                                                                                                               dlog
+                                                                                                                       </a>
+                                                                                                               </h4>
+                                                                                                       </td>
+                                                                                               </xsl:when>
+                                                                                               <xsl:otherwise>
+                                                                                                       <td colspan="4">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                               </xsl:otherwise>
+                                                                                       </xsl:choose>
+                                                                               </tr>
+                                                                               <xsl:for-each select=".//testcase">
+                                                                                       <xsl:sort select="@id" />
+                                                                                       <tr>
+                                                                                               <td>
+                                                                                                       <div
+                                                                                                               style="background-color:#F5DEB3;border:1px solid black;display:none;">
+                                                                                                               <xsl:attribute name="id"><xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <p>
+                                                                                                                       <xsl:for-each select="./description/steps//step">
+                                                                                                                               <xsl:sort select="@order" />
+                                                                                                                               <B>
+                                                                                                                                       Step
+                                                                                                                                       <xsl:value-of select="@order" />
+                                                                                                                                       :
+                                                                                                                               </B>
+                                                                                                                               <br />
+                                                                                                                               <xsl:value-of select=".//step_desc" />
+                                                                                                                               <br />
+                                                                                                                               <B>Expected:</B>
+                                                                                                                               <xsl:value-of select=".//expected" />
+                                                                                                                               <br />
+                                                                                                                       </xsl:for-each>
+                                                                                                               </p>
+                                                                                                               <p>
+                                                                                                                       <br />
+                                                                                                                       <B>
+                                                                                                                               Entry:
+                                                                                                                               <br />
+                                                                                                                       </B>
+                                                                                                                       <xsl:value-of select="./description//test_script_entry" />
+                                                                                                                       <br />
+                                                                                                               </p>
+                                                                                                       </div>
+                                                                                                       <a href="#" class="test_case_popup">
+                                                                                                               <xsl:attribute name="id"><xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <xsl:value-of select="@id" />
+                                                                                                       </a>
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:value-of select="@purpose" />
+                                                                                               </td>
+
+                                                                                               <xsl:choose>
+                                                                                                       <xsl:when test="@result">
+                                                                                                               <xsl:if test="@result = 'FAIL'">
+                                                                                                                       <td class="red_rate">
+                                                                                                                               <xsl:value-of select="@result" />
+                                                                                                                       </td>
+                                                                                                               </xsl:if>
+                                                                                                               <xsl:if test="@result = 'PASS'">
+                                                                                                                       <td class="green_rate">
+                                                                                                                               <xsl:value-of select="@result" />
+                                                                                                                       </td>
+                                                                                                               </xsl:if>
+                                                                                                               <xsl:if test="@result = 'BLOCK' ">
+                                                                                                                       <td class="orange_rate">
+                                                                                                                               BLOCK
+                                                                                                                       </td>
+                                                                                                               </xsl:if>
+                                                                                                               <xsl:if
+                                                                                                                       test="@result != 'BLOCK' and @result != 'FAIL' and @result != 'PASS' ">
+                                                                                                                       <td class="gray_rate">
+                                                                                                                               Not Run
+                                                                                                                       </td>
+                                                                                                               </xsl:if>
+                                                                                                       </xsl:when>
+                                                                                                       <xsl:otherwise>
+                                                                                                               <td>
+
+                                                                                                               </td>
+                                                                                                       </xsl:otherwise>
+                                                                                               </xsl:choose>
+                                                                                               <td>
+                                                                                                       <xsl:call-template name="br-replace">
+                                                                                                               <xsl:with-param name="word"
+                                                                                                                       select=".//result_info/stderr" />
+                                                                                                       </xsl:call-template>
+                                                                                                       <xsl:if test=".//result_info/stderr = ''">
+                                                                                                               N/A
+                                                                                                       </xsl:if>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                               </xsl:for-each>
+                                                                       </xsl:for-each>
+                                                               </table>
+                                                       </xsl:for-each>
+                                               </div>
+                                               <div id="see_fail" style="display:none;">
+                                                       <xsl:for-each select="test_definition/suite">
+                                                               <xsl:sort select="@name" />
+                                                               <div id="suite_title">
+                                                                       <h2>
+                                                                               Test Suite:
+                                                                               <xsl:value-of select="@name" />
+                                                                               (Failed only)
+                                                                       </h2>
+                                                                       <a>
+                                                                               <xsl:attribute name="name">
+                                                                     <xsl:value-of
+                                                                                       select="@name" />
+                                                                  </xsl:attribute>
+                                                                       </a>
+                                                               </div>
+                                                               <table>
+                                                                       <tr>
+                                                                               <th>Case_ID</th>
+                                                                               <th>Purpose</th>
+                                                                               <th>Result</th>
+                                                                               <th>Stderr</th>
+                                                                       </tr>
+                                                                       <xsl:for-each select=".//set">
+                                                                               <xsl:sort select="@name" />
+                                                                               <tr>
+                                                                                       <xsl:choose>
+                                                                                               <xsl:when test="@name">
+                                                                                                       <td colspan="3">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                                       <td colspan="1">
+                                                                                                               <h4>
+                                                                                                                       <a>
+                                                                                                                               <xsl:attribute name="href"><xsl:value-of
+                                                                                                                                       select="@set_debug_msg" /></xsl:attribute>
+                                                                                                                               dlog
+                                                                                                                       </a>
+                                                                                                               </h4>
+                                                                                                       </td>
+                                                                                               </xsl:when>
+                                                                                               <xsl:otherwise>
+                                                                                                       <td colspan="4">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                               </xsl:otherwise>
+                                                                                       </xsl:choose>
+                                                                               </tr>
+                                                                               <xsl:for-each select=".//testcase[@result='FAIL']">
+                                                                                       <xsl:sort select="@id" />
+                                                                                       <tr>
+                                                                                               <td>
+                                                                                                       <div
+                                                                                                               style="background-color:#F5DEB3;border:1px solid black;display:none;">
+                                                                                                               <xsl:attribute name="id">fail_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <p>
+                                                                                                                       <xsl:for-each select="./description/steps//step">
+                                                                                                                               <xsl:sort select="@order" />
+                                                                                                                               <B>
+                                                                                                                                       Step
+                                                                                                                                       <xsl:value-of select="@order" />
+                                                                                                                                       :
+                                                                                                                               </B>
+                                                                                                                               <br />
+                                                                                                                               <xsl:value-of select=".//step_desc" />
+                                                                                                                               <br />
+                                                                                                                               <B>Expected:</B>
+                                                                                                                               <xsl:value-of select=".//expected" />
+                                                                                                                               <br />
+                                                                                                                       </xsl:for-each>
+                                                                                                               </p>
+                                                                                                               <p>
+                                                                                                                       <br />
+                                                                                                                       <B>
+                                                                                                                               Entry:
+                                                                                                                               <br />
+                                                                                                                       </B>
+                                                                                                                       <xsl:value-of select="./description//test_script_entry" />
+                                                                                                                       <br />
+                                                                                                               </p>
+                                                                                                       </div>
+                                                                                                       <a href="#" class="test_case_popup">
+                                                                                                               <xsl:attribute name="id">fail_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <xsl:value-of select="@id" />
+                                                                                                       </a>
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:value-of select="@purpose" />
+                                                                                               </td>
+
+                                                                                               <td class="red_rate">
+                                                                                                       <xsl:value-of select="@result" />
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:call-template name="br-replace">
+                                                                                                               <xsl:with-param name="word"
+                                                                                                                       select=".//result_info/stderr" />
+                                                                                                       </xsl:call-template>
+                                                                                                       <xsl:if test=".//result_info/stderr = ''">
+                                                                                                               N/A
+                                                                                                       </xsl:if>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                               </xsl:for-each>
+                                                                       </xsl:for-each>
+                                                               </table>
+                                                       </xsl:for-each>
+                                               </div>
+                                               <div id="see_block" style="display:none;">
+                                                       <xsl:for-each select="test_definition/suite">
+                                                               <xsl:sort select="@name" />
+                                                               <div id="suite_title">
+                                                                       <h2>
+                                                                               Test Suite:
+                                                                               <xsl:value-of select="@name" />
+                                                                               (Blocked Only)
+                                                                       </h2>
+                                                                       <a>
+                                                                               <xsl:attribute name="name">
+                                                                     <xsl:value-of
+                                                                                       select="@name" />
+                                                                  </xsl:attribute>
+                                                                       </a>
+                                                               </div>
+                                                               <table>
+                                                                       <tr>
+                                                                               <th>Case_ID</th>
+                                                                               <th>Purpose</th>
+                                                                               <th>Result</th>
+                                                                               <th>Stderr</th>
+                                                                       </tr>
+                                                                       <xsl:for-each select=".//set">
+                                                                               <xsl:sort select="@name" />
+                                                                               <tr>
+                                                                                       <xsl:choose>
+                                                                                               <xsl:when test="@name">
+                                                                                                       <td colspan="3">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                                       <td colspan="1">
+                                                                                                               <h4>
+                                                                                                                       <a>
+                                                                                                                               <xsl:attribute name="href"><xsl:value-of
+                                                                                                                                       select="@set_debug_msg" /></xsl:attribute>
+                                                                                                                               dlog
+                                                                                                                       </a>
+                                                                                                               </h4>
+                                                                                                       </td>
+                                                                                               </xsl:when>
+                                                                                               <xsl:otherwise>
+                                                                                                       <td colspan="4">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                               </xsl:otherwise>
+                                                                                       </xsl:choose>
+                                                                               </tr>
+                                                                               <xsl:for-each select=".//testcase[@result='BLOCK']">
+                                                                                       <xsl:sort select="@id" />
+                                                                                       <tr>
+                                                                                               <td>
+                                                                                                       <div
+                                                                                                               style="background-color:#F5DEB3;border:1px solid black;display:none;">
+                                                                                                               <xsl:attribute name="id">block_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <p>
+                                                                                                                       <xsl:for-each select="./description/steps//step">
+                                                                                                                               <xsl:sort select="@order" />
+                                                                                                                               <B>
+                                                                                                                                       Step
+                                                                                                                                       <xsl:value-of select="@order" />
+                                                                                                                                       :
+                                                                                                                               </B>
+                                                                                                                               <br />
+                                                                                                                               <xsl:value-of select=".//step_desc" />
+                                                                                                                               <br />
+                                                                                                                               <B>Expected:</B>
+                                                                                                                               <xsl:value-of select=".//expected" />
+                                                                                                                               <br />
+                                                                                                                       </xsl:for-each>
+                                                                                                               </p>
+                                                                                                               <p>
+                                                                                                                       <br />
+                                                                                                                       <B>
+                                                                                                                               Entry:
+                                                                                                                               <br />
+                                                                                                                       </B>
+                                                                                                                       <xsl:value-of select="./description//test_script_entry" />
+                                                                                                                       <br />
+                                                                                                               </p>
+                                                                                                       </div>
+                                                                                                       <a href="#" class="test_case_popup">
+                                                                                                               <xsl:attribute name="id">block_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <xsl:value-of select="@id" />
+                                                                                                       </a>
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:value-of select="@purpose" />
+                                                                                               </td>
+
+                                                                                               <td class="orange_rate">
+                                                                                                       <xsl:value-of select="@result" />
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:call-template name="br-replace">
+                                                                                                               <xsl:with-param name="word"
+                                                                                                                       select=".//result_info/stderr" />
+                                                                                                       </xsl:call-template>
+                                                                                                       <xsl:if test=".//result_info/stderr = ''">
+                                                                                                               N/A
+                                                                                                       </xsl:if>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                               </xsl:for-each>
+                                                                       </xsl:for-each>
+                                                               </table>
+                                                       </xsl:for-each>
+                                               </div>
+                                               <div id="see_na" style="display:none;">
+                                                       <xsl:for-each select="test_definition/suite">
+                                                               <xsl:sort select="@name" />
+                                                               <div id="suite_title">
+                                                                       <h2>
+                                                                               Test Suite:
+                                                                               <xsl:value-of select="@name" />
+                                                                               (Not executed Only)
+                                                                       </h2>
+                                                                       <a>
+                                                                               <xsl:attribute name="name">
+                                                                     <xsl:value-of
+                                                                                       select="@name" />
+                                                                  </xsl:attribute>
+                                                                       </a>
+                                                               </div>
+                                                               <table>
+                                                                       <tr>
+                                                                               <th>Case_ID</th>
+                                                                               <th>Purpose</th>
+                                                                               <th>Result</th>
+                                                                               <th>Stderr</th>
+                                                                       </tr>
+                                                                       <xsl:for-each select=".//set">
+                                                                               <xsl:sort select="@name" />
+                                                                               <tr>
+                                                                                       <xsl:choose>
+                                                                                               <xsl:when test="@name">
+                                                                                                       <td colspan="3">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                                       <td colspan="1">
+                                                                                                               <h4>
+                                                                                                                       <a>
+                                                                                                                               <xsl:attribute name="href"><xsl:value-of
+                                                                                                                                       select="@set_debug_msg" /></xsl:attribute>
+                                                                                                                               dlog
+                                                                                                                       </a>
+                                                                                                               </h4>
+                                                                                                       </td>
+                                                                                               </xsl:when>
+                                                                                               <xsl:otherwise>
+                                                                                                       <td colspan="4">
+                                                                                                               <h3>
+                                                                                                                       Test Set:
+                                                                                                                       <xsl:value-of select="@name" />
+                                                                                                               </h3>
+                                                                                                       </td>
+                                                                                               </xsl:otherwise>
+                                                                                       </xsl:choose>
+                                                                               </tr>
+                                                                               <xsl:for-each select=".//testcase[@result='N/A']">
+                                                                                       <xsl:sort select="@id" />
+                                                                                       <tr>
+                                                                                               <td>
+                                                                                                       <div
+                                                                                                               style="background-color:#F5DEB3;border:1px solid black;display:none;">
+                                                                                                               <xsl:attribute name="id">na_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <p>
+                                                                                                                       <xsl:for-each select="./description/steps//step">
+                                                                                                                               <xsl:sort select="@order" />
+                                                                                                                               <B>
+                                                                                                                                       Step
+                                                                                                                                       <xsl:value-of select="@order" />
+                                                                                                                                       :
+                                                                                                                               </B>
+                                                                                                                               <br />
+                                                                                                                               <xsl:value-of select=".//step_desc" />
+                                                                                                                               <br />
+                                                                                                                               <B>Expected:</B>
+                                                                                                                               <xsl:value-of select=".//expected" />
+                                                                                                                               <br />
+                                                                                                                       </xsl:for-each>
+                                                                                                               </p>
+                                                                                                               <p>
+                                                                                                                       <br />
+                                                                                                                       <B>
+                                                                                                                               Entry:
+                                                                                                                               <br />
+                                                                                                                       </B>
+                                                                                                                       <xsl:value-of select="./description//test_script_entry" />
+                                                                                                                       <br />
+                                                                                                               </p>
+                                                                                                       </div>
+                                                                                                       <a href="#" class="test_case_popup">
+                                                                                                               <xsl:attribute name="id">na_<xsl:value-of
+                                                                                                                       select="@id" /></xsl:attribute>
+                                                                                                               <xsl:value-of select="@id" />
+                                                                                                       </a>
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:value-of select="@purpose" />
+                                                                                               </td>
+
+                                                                                               <td class="gray_rate">
+                                                                                                       <xsl:value-of select="@result" />
+                                                                                               </td>
+                                                                                               <td>
+                                                                                                       <xsl:call-template name="br-replace">
+                                                                                                               <xsl:with-param name="word"
+                                                                                                                       select=".//result_info/stderr" />
+                                                                                                       </xsl:call-template>
+                                                                                                       <xsl:if test=".//result_info/stderr = ''">
+                                                                                                               N/A
+                                                                                                       </xsl:if>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                               </xsl:for-each>
+                                                                       </xsl:for-each>
+                                                               </table>
+                                                       </xsl:for-each>
+                                               </div>
+                                       </div>
+                               </div>
+                               <div id="goTopBtn">
+                                       <img border="0" src="./style/back_top.png" />
+                               </div>
+                               <script type="text/javascript" src="./style/application.js" />
+                               <script language="javascript" type="text/javascript">
+                                       $(document).ready(function(){
+                                       goTopEx();
+                                       });
+                               </script>
+                       </body>
+               </html>
+       </xsl:template>
+       <xsl:template name="br-replace">
+               <xsl:param name="word" />
+               <xsl:variable name="cr">
+                       <xsl:text>\n</xsl:text>
+               </xsl:variable>
+               <xsl:choose>
+                       <xsl:when test="contains($word,$cr)">
+                               <xsl:value-of select="substring-before($word,$cr)" />
+                               <br />
+                               <xsl:call-template name="br-replace">
+                                       <xsl:with-param name="word" select="substring-after($word,$cr)" />
+                               </xsl:call-template>
+                       </xsl:when>
+                       <xsl:otherwise>
+                               <xsl:value-of select="$word" />
+                       </xsl:otherwise>
+               </xsl:choose>
+       </xsl:template>
+</xsl:stylesheet>
diff --git a/automated-tests/style/tests.css b/automated-tests/style/tests.css
new file mode 100644 (file)
index 0000000..487bca0
--- /dev/null
@@ -0,0 +1,195 @@
+@charset "UTF-8";\r
+/* CSS Document */\r
+#testcasepage div,#testcasepage h1,#testcasepage p,#testcasepage table,#testcasepage tr,#testcasepage th,#testcasepage td\r
+       {\r
+       margin: 0;\r
+       padding: 0;\r
+       border: 0;\r
+       font-weight: inherit;\r
+       font-style: inherit;\r
+       font-size: 0.96em;\r
+       font-family: arial;\r
+       vertical-align: baseline;\r
+}\r
+\r
+#title td, #btc td{\r
+       margin: 0;\r
+       padding: 0;\r
+       border: 0;\r
+       font-weight: inherit;\r
+       font-style: inherit;\r
+       font-size: 0.96em;\r
+       font-family: arial;\r
+       vertical-align: baseline;\r
+}\r
+\r
+td.Ratio {\r
+       text-align: left;\r
+       font-weight: normal;\r
+       padding: 4px 10px 4px 5px;\r
+       vertical-align: middle;\r
+}\r
+\r
+th.Ratio {\r
+       width: 400px;\r
+}\r
+\r
+#testcasepage p {\r
+       text-align: left;\r
+}\r
+\r
+#suite_title {\r
+       text-align: left;\r
+}\r
+\r
+#btc {\r
+       text-align: right;\r
+}\r
+\r
+#btc table {\r
+       position: absolute;\r
+       right: 0px;\r
+       width: 600px;\r
+}\r
+\r
+#testcasepage table {\r
+       border-collapse: separate;\r
+       border-spacing: 0;\r
+       margin-bottom: 1.4em;\r
+       vertical-align: middle;\r
+}\r
+\r
+#testcasepage th,#testcasepage td {\r
+       text-align: left;\r
+       font-weight: normal;\r
+       padding: 4px 10px 4px 5px;\r
+       vertical-align: middle;\r
+}\r
+\r
+#cases table {\r
+       width: 101%;\r
+}\r
+\r
+#cases td {\r
+       border-left: 0px;\r
+       font-weight: normal;\r
+       border-bottom: 0px;\r
+}\r
+\r
+#suite_summary table {\r
+       width: 100%;\r
+}\r
+\r
+\r
+#overview table {\r
+       width: 101%;\r
+}\r
+\r
+#overview table, #overview td, #overview tr {\r
+       border-left: none;\r
+       border-bottom: none;\r
+       border-right: none;\r
+       vertical-align: top;\r
+}\r
+\r
+#overview td{\r
+       width: 50%;\r
+}\r
+\r
+#capability table {\r
+       width: 50%;\r
+}\r
+\r
+#fail_cases table {\r
+       width: 101%;\r
+}\r
+\r
+#title table {\r
+       width: 101%;\r
+}\r
+\r
+#device table {\r
+       width: 100%;\r
+}\r
+\r
+#summary table {\r
+       width: 100%;\r
+}\r
+\r
+#testcasepage th {\r
+       border-bottom: 1px solid #000;\r
+       background-color: #AAAAAA;\r
+       border-left: 1px solid #000;\r
+       border-top: 1px solid #000;\r
+       color: #000;\r
+       font-weight: bold;\r
+       vertical-align: bottom;\r
+}\r
+\r
+#summary th:last-child,#summary td:last-child, #device th:last-child,#device td:last-child, #suite_summary th:last-child,#suite_summary td:last-child,#cases th:last-child,#cases td:last-child,#capability th:last-child,#capability td:last-child {\r
+       border-right: 1px solid #000;\r
+}\r
+\r
+#testcasepage td {\r
+       font-weight: normal;\r
+}\r
+\r
+#summary td, #device td, #capability td, #suite_summary td, #cases td{\r
+       border-left: 1px solid;\r
+       font-weight: normal;\r
+       border-bottom: 1px solid;\r
+}\r
+\r
+#testcasepage td.yellow_rate {\r
+       background-color: #ffcc00;\r
+}\r
+\r
+#testcasepage td.green_rate {\r
+       background-color: #1E90FF;\r
+}\r
+\r
+#testcasepage td.dgreen_rate {\r
+       background-color: #339933;\r
+}\r
+\r
+#testcasepage td.red_rate {\r
+       background-color: #FF3333;\r
+}\r
+\r
+#testcasepage td.orange_rate {\r
+       background-color: #FFA500;\r
+}\r
+\r
+#testcasepage td.gray_rate {\r
+       background-color: #AAAAAA;\r
+}\r
+\r
+#title table,#title tr,#title td {\r
+       border-left: none;\r
+       border-bottom: none;\r
+       text-align: center;\r
+}\r
+\r
+#title td:last-child {\r
+       border-right: none;\r
+}\r
+\r
+#testcasepage h1 {\r
+       font-size: 2em;\r
+       font-family: Arial, sans-serif;\r
+       font-weight: bold;\r
+       line-height: 1;\r
+       color: #000;\r
+       margin-bottom: 0.75em;\r
+       padding-top: 0.25em;\r
+       font-weight: bold;\r
+}\r
+\r
+#goTopBtn {\r
+       right: 0px;\r
+       bottom: 0px;\r
+       position: fixed; +\r
+       position: absolute;\r
+       top: expression(parseInt(document.body.scrollTop)+document.body.clientHeight-40\r
+               );\r
+}\r
diff --git a/automated-tests/tcbuild b/automated-tests/tcbuild
new file mode 120000 (symlink)
index 0000000..89c2de7
--- /dev/null
@@ -0,0 +1 @@
+scripts/tcbuild.sh
\ No newline at end of file
diff --git a/automated-tests/templates/tct-package/README b/automated-tests/templates/tct-package/README
new file mode 100644 (file)
index 0000000..0af341f
--- /dev/null
@@ -0,0 +1,43 @@
+The scripts contained in the automated-tests/scripts folder are based on
+the Web Application Security & Privacy module test suite from Intel,
+with the following license:
+
+----------------------------------------------
+License
+----------------------------------------------
+Copyright (c) 2012 Intel Corporation.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of works must retain the original copyright notice, this list
+  of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the original copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors
+  may be used to endorse or promote products derived from this work without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "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 INTEL CORPORATION 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.
+
+Authors:
+        Yue, Jianhui <jianhuix.a.yue@intel.com>
+
+Modifications to scripts:
+Added mechanism to build and execute tests with finer granularity.
+Added option to generate tests for executing on desktop
+
+Copyright (c) 2014 Samsung Electronics Co., Ltd.
+
+Authors:
+        Steele, David <david.steele@partner.samsung.com>
diff --git a/automated-tests/templates/tct-package/inst.sh b/automated-tests/templates/tct-package/inst.sh
new file mode 100755 (executable)
index 0000000..c2888df
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+NAME=$(basename $(cd $(dirname $0);pwd))
+PKG_DIR=%{PKG_DIR} # directory supplied by external script
+PKG_NAME=%{PKG_NAME} # name supplied by external script
+PKG_FULLNAME=%{PKG_FULLNAME} # name supplied by external script
+
+#parse params
+USAGE="Usage: ./inst.sh [-i] [-u]
+  -i install wgt and config environment
+  -u uninstall wgt and remove source file
+[-i] option was set as default."
+
+function installpkg(){
+    rpm -e `rpm -qa | grep $PKG_NAME`
+    rpm -ivh --quiet /$PKG_DIR/$PKG_FULLNAME
+    /tmp/add_all_smack_rule.sh
+}
+
+function uninstallpkg(){
+### remove source file ###
+if [ -d /opt/usr/media/tct/opt/$NAME ];then
+    rm -rf /opt/usr/media/tct/opt/$NAME
+    rpm -e $PKG_NAME
+else
+    echo "Remove source file fail, please check if the source file exist: /opt/usr/media/tct/opt/$NAME ..."
+fi
+}
+
+case "$1" in
+    -h|--help) echo "$USAGE"
+               exit ;;
+    ""|-i) installpkg;;
+    -u) uninstallpkg;;
+    *) echo "Unknown option: $1"
+       echo "$USAGE"
+       exit ;;
+esac
diff --git a/build/tizen/.gitignore b/build/tizen/.gitignore
new file mode 100644 (file)
index 0000000..0d1f029
--- /dev/null
@@ -0,0 +1,20 @@
+/doc
+/.cov
+/aclocal.m4
+/autom4te.cache
+/ar-lib
+/compile
+/config.guess
+/config.log
+/config.status
+/config.sub
+/configure
+/depcomp
+/documentation.list
+/install-sh
+/libtool
+/ltmain.sh
+/m4
+/missing
+*.pc
+/documentation.list
diff --git a/build/tizen/Makefile.am b/build/tizen/Makefile.am
new file mode 100644 (file)
index 0000000..1aa98f0
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2014 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+SUBDIRS = adaptor
+
+if USE_PLUGIN
+SUBDIRS += plugins
+endif
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = dali.pc
+
+MAINTAINERCLEANFILES = \
+    aclocal.m4 \
+    autom4te.cache \
+    config.guess \
+    config.sub \
+    configure \
+    depcomp \
+    install-sh \
+    ltmain.sh \
+    missing \
+    `find "$(srcdir)" -type f -name Makefile.in -print` \
+    `find . \( -name "*.gcov" -o -name "*.gcno" -o -name "*.gcda" \) -print`
+
+CLEANFILES = \
+       `find . \( -name "*.gcov" -o -name "*.gcno" -o -name "*.gcda" \) -print`
+
+COVERAGE_DIR=.cov
+COVERAGE_OUTPUT_DIR=doc/coverage
+
+# From lcov version 1.10 onwards, branch coverage is off by default and earlier versions do not support the rc option
+LCOV_OPTS=`if [ \`printf "\\\`lcov --version | cut -d' ' -f4\\\`\n1.10\n" | sort -V | head -n 1\` = 1.10 ] ; then echo "--rc lcov_branch_coverage=1" ; fi`
+
+cov_data:
+       @test -z $(COVERAGE_DIR) || mkdir -p $(COVERAGE_DIR)
+       @rm -f $(COVERAGE_DIR)/*
+       @-cp adaptor/.libs/*.gcda adaptor/.libs/*.gcno  $(COVERAGE_DIR)
+       @for i in `find $(COVERAGE_DIR) -name "libdali_adaptor_la-*.gcda" -o -name "libdali_adaptor_la-*.gcno"` ;\
+               do mv $$i `echo $$i | sed s/libdali_adaptor_la-//` ; echo $$i ; done
+       @cd $(COVERAGE_DIR) ; lcov $(LCOV_OPTS) --base-directory . --directory . -c -o dali.info
+       @cd $(COVERAGE_DIR) ; lcov $(LCOV_OPTS) --remove dali.info "*/dali-env/*" "/usr/include/*" -o dali.info
+       @test -z $(COVERAGE_OUTPUT_DIR) || mkdir -p $(COVERAGE_OUTPUT_DIR)
+
+coverage: cov_data
+       @genhtml $(LCOV_OPTS) -o $(COVERAGE_OUTPUT_DIR) $(COVERAGE_DIR)/dali.info
+
+reset_coverage:
+       @lcov -z --directory `pwd`
diff --git a/build/tizen/adaptor/Makefile.am b/build/tizen/adaptor/Makefile.am
new file mode 100644 (file)
index 0000000..e45ad1d
--- /dev/null
@@ -0,0 +1,440 @@
+#
+# Copyright (c) 2014 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Build the Dali Adaptor library
+
+
+############# INCLUDE FILE LISTS #############
+
+# Base Adaptor
+base_adaptor_src_dir = ../../../adaptors/base
+include ../../../adaptors/base/file.list
+
+# Platform Abstraction
+tizen_platform_abstraction_src_dir = ../../../platform-abstractions/tizen
+portable_platform_abstraction_src_dir = ../../../platform-abstractions/portable
+include ../../../platform-abstractions/tizen/file.list
+
+# Text Abstraction
+text_src_dir = ../../../text
+include ../../../text/file.list
+
+# Integration
+adaptor_integration_api_dir = ../../../adaptors/integration-api
+include ../../../adaptors/integration-api/file.list
+
+# Internal Common
+adaptor_common_dir = ../../../adaptors/common
+include ../../../adaptors/common/file.list
+
+# Wayland
+if WAYLAND
+adaptor_wayland_dir = ../../../adaptors/wayland
+include ../../../adaptors/wayland/file.list
+else
+# X11
+adaptor_x11_dir = ../../../adaptors/x11
+include ../../../adaptors/x11/file.list
+endif
+
+# Ubuntu
+if UBUNTU_PROFILE
+adaptor_ubuntu_dir = ../../../adaptors/ubuntu
+include ../../../adaptors/ubuntu/file.list
+else
+# Tizen
+adaptor_tizen_dir = ../../../adaptors/tizen
+include ../../../adaptors/tizen/file.list
+endif
+
+# Mobile
+adaptor_mobile_dir = ../../../adaptors/mobile
+include ../../../adaptors/mobile/file.list
+
+# TV
+if TV_PROFILE
+adaptor_tv_dir = ../../../adaptors/tv
+include ../../../adaptors/tv/file.list
+endif
+
+# Public API
+adaptor_public_api_dir = ../../../adaptors/public-api
+include ../../../adaptors/public-api/file.list
+
+# Devel API ( for use by Toolkit)
+adaptor_devel_api_dir = ../../../adaptors/devel-api
+include ../../../adaptors/devel-api/file.list
+
+
+# Static libraries
+static_libraries_libunibreak_src_dir = ../../../text/dali/internal/libunibreak
+include ../../../text/dali/internal/libunibreak/file.list
+
+############# source files #############
+
+# COMMON
+if COMMON_PROFILE
+
+adaptor_internal_src_files = $(adaptor_common_internal_src_files) \
+                             $(adaptor_common_internal_default_profile_src_files) \
+                             $(adaptor_tizen_internal_src_files) \
+                             $(static_libraries_libunibreak_src_files)
+
+if WAYLAND
+adaptor_internal_src_files += $(adaptor_wayland_tizen_internal_src_files) \
+                              $(adaptor_wayland_internal_default_profile_src_files)
+else
+adaptor_internal_src_files += $(adaptor_x11_tizen_internal_src_files) \
+                              $(adaptor_x11_internal_default_profile_src_files)
+endif # WAYLAND
+endif # COMMON_PROFILE
+
+
+# UBUNTU
+if UBUNTU_PROFILE
+
+adaptor_internal_src_files = $(adaptor_common_internal_src_files) \
+                             $(adaptor_common_internal_default_profile_src_files) \
+                             $(adaptor_ubuntu_internal_src_files) \
+                             $(adaptor_x11_ubuntu_internal_src_files) \
+                             $(adaptor_x11_internal_default_profile_src_files) \
+                             $(static_libraries_libunibreak_src_files)
+
+endif # UBUNTU_PROFILE
+
+
+# MOBILE
+if MOBILE_PROFILE
+
+adaptor_internal_src_files = $(adaptor_common_internal_src_files) \
+                             $(adaptor_common_internal_mobile_profile_src_files) \
+                             $(adaptor_tizen_internal_src_files) \
+                             $(static_libraries_libunibreak_src_files)
+
+if WAYLAND
+adaptor_internal_src_files += $(adaptor_wayland_tizen_internal_src_files)
+else
+adaptor_internal_src_files += $(adaptor_x11_tizen_internal_src_files)
+endif # WAYLAND
+
+endif # MOBILE_PROFILE
+
+# WEARABLE
+if WEARABLE_PROFILE
+
+adaptor_internal_src_files = $(adaptor_common_internal_src_files) \
+                             $(adaptor_common_internal_mobile_profile_src_files) \
+                             $(adaptor_tizen_internal_src_files) \
+                             $(static_libraries_libunibreak_src_files)
+if WAYLAND
+adaptor_internal_src_files += $(adaptor_wayland_tizen_internal_src_files)
+else
+adaptor_internal_src_files += $(adaptor_x11_tizen_internal_src_files)
+endif # WAYLAND
+
+endif # WEARABLE
+
+
+# TV
+if TV_PROFILE
+
+adaptor_internal_src_files = $(adaptor_common_internal_src_files) \
+                             $(adaptor_common_internal_tv_profile_src_files) \
+                             $(adaptor_tizen_internal_src_files) \
+                             $(static_libraries_libunibreak_src_files)
+if WAYLAND
+adaptor_internal_src_files += $(adaptor_wayland_tizen_internal_src_files)
+else
+adaptor_internal_src_files += $(adaptor_x11_tv_internal_src_files) \
+                             $(adaptor_x11_internal_tv_profile_key_src_files)
+endif # WAYLAND
+
+endif
+
+# Node JS support for using an external libuv main loop. If not enabled then just use e-core as normal
+# Used for things like callbacks, file-monintors, x input handling
+if LIB_UV_EVENT_LOOP
+main_loop_integration_src_files = $(adaptor_common_internal_uv_src_files)
+input_event_handler_src_files = $(adaptor_uv_x_event_handler_internal_src_files)
+else
+main_loop_integration_src_files = $(adaptor_common_internal_ecore_src_files)
+input_event_handler_src_files = $(adaptor_ecore_x_event_handler_internal_src_files)
+endif
+
+
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = dali-adaptor-integration.pc
+
+lib_LTLIBRARIES = libdali-adaptor.la
+
+libdali_adaptor_la_SOURCES = \
+                     $(base_adaptor_src_files) \
+                     $(main_loop_integration_src_files) \
+                     $(tizen_platform_abstraction_src_files) \
+                     $(text_abstraction_src_files) \
+                     $(devel_api_src_files) \
+                     $(public_api_src_files) \
+                     $(adaptor_internal_src_files) \
+                     $(input_event_handler_src_files)
+
+
+if ENABLE_NETWORK
+libdali_adaptor_la_SOURCES += \
+  $(base_adaptor_networking_src_files)
+endif
+
+libdali_adaptor_la_DEPENDENCIES =
+
+# List include directories with more platform-specific (tizen) before portable root:
+libdali_adaptor_la_includes = \
+                      -I../../.. \
+                      -I../../../platform-abstractions/tizen \
+                      -I../../../platform-abstractions/tizen/resource-loader \
+                      -I../../../platform-abstractions/portable \
+                      -I../../../platform-abstractions/ \
+                      -I../../../adaptors/public-api \
+                      -I../../../adaptors/integration-api \
+                      -I../../../adaptors/public-api/adaptor-framework \
+                      -I../../../adaptors/devel-api/adaptor-framework \
+                      -I../../../adaptors/common \
+                      -I../../../adaptors/base/interfaces \
+                      -I../../../adaptors/ \
+                      -I../../../text \
+                      -I../../../text/dali/internal/libunibreak
+
+if WAYLAND
+libdali_adaptor_la_includes += \
+                      -I../../../adaptors/wayland \
+                      -I../../../adaptors/integration-api/wayland
+else
+libdali_adaptor_la_includes += \
+                      -I../../../adaptors/x11 \
+                      -I../../../adaptors/integration-api/x11
+endif
+
+if UBUNTU_PROFILE
+libdali_adaptor_la_includes += \
+                      -I../../../adaptors/ubuntu
+else
+libdali_adaptor_la_includes += \
+                      -I../../../adaptors/tizen
+endif
+
+daliDefaultThemeDir  = ${dataReadWriteDir}/theme/
+daliShaderbinCacheDir = ${dataReadOnlyDir}/core/shaderbin/
+
+libdali_adaptor_la_CXXFLAGS = \
+                      -DDALI_DATA_RW_DIR="\"${daliReadWriteDir}\"" \
+                      -DDALI_DATA_RO_DIR="\"${daliReadOnlyDir}\"" \
+                      -DDALI_DEFAULT_FONT_CACHE_DIR="\"${daliDefaultFontCacheDir}\"" \
+                      -DDALI_USER_FONT_CACHE_DIR="\"${daliUserFontCacheDir}\"" \
+                      -DDALI_SHADERBIN_DIR="\"${daliShaderbinCacheDir}\"" \
+                      -DDALI_DEFAULT_THEME_DIR="\"${daliDefaultThemeDir}\"" \
+                      -DFONT_PRELOADED_PATH="\"${fontPreloadedPath}\"" \
+                      -DFONT_DOWNLOADED_PATH="\"${fontDownloadedPath}\"" \
+                      -DFONT_APPLICATION_PATH="\"${fontApplicationPath}\"" \
+                      -DFONT_CONFIGURATION_FILE="\"${fontConfigurationFile}\"" \
+                      -DNON_POWER_OF_TWO_TEXTURES \
+                      -DDALI_COMPILATION -DDALI_ADAPTOR_COMPILATION \
+                      -Werror -Wall -lgcc \
+                      $(libdali_adaptor_la_includes) \
+                      $(DALI_ADAPTOR_CFLAGS) \
+                      $(DALICORE_CFLAGS) \
+                      $(OPENGLES20_CFLAGS) \
+                      $(FREETYPE_CFLAGS) \
+                      $(FONTCONFIG_CFLAGS) \
+                      $(PNG_CFLAGS) \
+                      $(CAPI_APPFW_APPLICATION_CFLAGS) \
+                      $(CAPI_SYSTEM_INFO_CFLAGS) \
+                      $(ELEMENTARY_CFLAGS) \
+                      $(EVAS_CFLAGS) \
+                      $(ECORE_CFLAGS) \
+                      $(ECORE_IPC_CFLAGS) \
+                      $(DLOG_CFLAGS) \
+                      $(VCONF_CFLAGS) \
+                      $(EXIF_CFLAGS) \
+                      $(MMFSOUND_CFLAGS) \
+                      $(TTS_CFLAGS) \
+                      $(SENSOR_CFLAGS) \
+                      $(LIBDRM_CFLAGS) \
+                      $(LIBEXIF_CFLAGS) \
+                      $(LIBCURL_CFLAGS) \
+                      $(CAPI_SYSTEM_SYSTEM_SETTINGS_CFLAGS) \
+                      $(ELDBUS_CFLAGS)
+
+libdali_adaptor_la_CFLAGS = $(libdali_adaptor_la_CXXFLAGS)
+
+libdali_adaptor_la_LIBADD = \
+                      $(DALICORE_LIBS) \
+                      $(OPENGLES20_LIBS) \
+                      $(FREETYPE_LIBS) \
+                      $(FONTCONFIG_LIBS) \
+                      $(PNG_LIBS) \
+                      $(ELEMENTARY_LIBS) \
+                      $(ECORE_IPC_LIBS) \
+                      $(DLOG_LIBS) \
+                      $(VCONF_LIBS) \
+                      $(EXIF_LIBS) \
+                      $(TTS_LIBS) \
+                      $(SENSOR_LIBS) \
+                      $(LIBDRM_LIBS) \
+                      $(LIBEXIF_LIBS) \
+                      $(LIBCURL_LIBS) \
+                      $(CAPI_SYSTEM_SYSTEM_SETTINGS_LIBS) \
+                      $(CAPI_APPFW_APPLICATION_LIBS) \
+                      $(HARFBUZZ_LIBS) \
+                      $(CAPI_SYSTEM_INFO_LIBS) \
+                      $(ELDBUS_LIBS) \
+                      -lgif \
+                      -lpthread \
+                      -lboost_thread \
+                      -lturbojpeg
+
+if WAYLAND
+libdali_adaptor_la_CXXFLAGS += $(WAYLAND_CFLAGS)
+libdali_adaptor_la_LIBADD += $(WAYLAND_LIBS)
+else
+libdali_adaptor_la_CXXFLAGS += $(X11_CFLAGS)
+libdali_adaptor_la_LIBADD += $(X11_LIBS)
+libdali_adaptor_la_LIBADD += $(ECORE_X_LIBS)
+endif
+
+if COMMON_PROFILE
+libdali_adaptor_la_CXXFLAGS += $(HAPTIC_CFLAGS)
+endif
+
+if MOBILE_PROFILE
+libdali_adaptor_la_CXXFLAGS += \
+                      $(DEVICED_CFLAGS) \
+                      $(EFL_ASSIST_CFLAGS) \
+                      $(NATIVE_BUFFER_CFLAGS) \
+                      $(NATIVE_BUFFER_POOL_CFLAGS)
+
+libdali_adaptor_la_LIBADD += \
+                      $(EFL_ASSIST_LIBS) \
+                      $(NATIVE_BUFFER_LIBS) \
+                      $(NATIVE_BUFFER_POOL_LIBS)
+endif
+
+if WEARABLE_PROFILE
+libdali_adaptor_la_CXXFLAGS += \
+                      $(HAPTIC_CFLAGS) \
+                      $(EFL_ASSIST_CFLAGS)
+endif
+
+if TV_PROFILE
+libdali_adaptor_la_CXXFLAGS += $(HAPTIC_CFLAGS)
+libdali_adaptor_la_LIBADD +=
+endif
+
+if !UBUNTU_PROFILE
+if WAYLAND
+else
+# X11
+libdali_adaptor_la_CXXFLAGS += $(UTILX_CFLAGS)
+libdali_adaptor_la_LIBADD += $(UTILX_LIBS)
+endif
+endif
+if UBUNTU_PROFILE
+libdali_adaptor_la_LIBADD += -ljpeg
+CFLAGS += -fPIC
+endif
+
+tizenadaptorpublicapidir = $(devincludepath)/dali/public-api
+tizenadaptorpublicapi_HEADERS = $(public_api_header_files)
+
+tizenadaptordevelapidir= $(devincludepath)/dali/devel-api
+
+tizenadaptorintegrationapidir = $(devincludepath)/dali/integration-api/adaptors
+tizenadaptorintegrationapi_HEADERS = $(adaptor_integration_api_header_files)
+
+if WAYLAND
+tizenadaptorintegrationwaylandapidir = $(devincludepath)/dali/integration-api/adaptors
+tizenadaptorintegrationwaylandapi_HEADERS = $(adaptor_integration_wayland_api_header_files)
+else
+tizenadaptorintegrationx11apidir = $(devincludepath)/dali/integration-api/adaptors
+tizenadaptorintegrationx11api_HEADERS = $(adaptor_integration_x11_api_header_files)
+endif
+
+tizenadaptorframeworkpublicapidir = $(tizenadaptorpublicapidir)/adaptor-framework
+tizenadaptorframeworkpublicapi_HEADERS = $(public_api_adaptor_framework_header_files)
+
+tizenadaptorframeworkdevelapidir = $(tizenadaptordevelapidir)/adaptor-framework
+tizenadaptorframeworkdevelapi_HEADERS = $(devel_api_adaptor_framework_header_files)
+
+tizentextabstractiondevelapidir = $(tizenadaptordevelapidir)/text-abstraction
+tizentextabstractiondevelapi_HEADERS = $(text_abstraction_header_files)
+
+if !UBUNTU_PROFILE
+tizenadaptorframeworkpublicapi_HEADERS += $(public_api_adaptor_tizen_header_files)
+
+if !WAYLAND
+tizenadaptorframeworkdevelapi_HEADERS += $(devel_api_adaptor_tizen_x11_header_files)
+endif # NOT WAYLAND
+
+endif # NOT UBUNTU_PROFILE
+
+tizenadaptordaliheaderdir = $(devincludepath)/dali
+tizenadaptordaliheader_HEADERS = $(adaptor_dali_header_file)
+
+install-data-local:
+       $(MKDIR_P) ${DESTDIR}/${daliUserFontCacheDir} ${DESTDIR}/${daliShaderbinCacheDir}
+
+# Install resource log analyzer script
+bin_SCRIPTS = ../../../adaptors/scripts/dalireslog.sh
+
+# linking test
+
+# turn off the linker test if were building for libuv
+# We can't link to LibUV becase it is statically linked to Node.JS (by default)
+if !LIB_UV_EVENT_LOOP
+noinst_PROGRAMS = linker.test
+endif # NOT LIB_UV_EVENT_LOOP
+
+linker_test_SOURCES = linker-test.cpp
+
+linker_test_CXXFLAGS = \
+  -DDALI_ADAPTOR_COMPILATION \
+  -I../../../adaptors/common \
+  -I../../../adaptors/public-api \
+  -I../../../adaptors/integration-api \
+  -I../../../adaptors/base/interfaces \
+  -I../../../adaptors/public-api/adaptor-framework \
+  -I../../../adaptors/devel-api/adaptor-framework \
+  $(DALI_ADAPTOR_CFLAGS) \
+  $(DALICORE_CFLAGS) \
+  $(VCONF_CFLAGS) \
+  $(DALIX11_CFLAGS) \
+  -Werror -Wall
+
+if WAYLAND
+linker_test_CXXFLAGS += \
+  -I../../../adaptors/integration-api/wayland
+else
+
+linker_test_CXXFLAGS += \
+  -I../../../adaptors/integration-api/x11
+endif
+
+
+linker_test_DEPENDENCIES = libdali-adaptor.la
+linker_test_LDADD = \
+  $(DALICORE_LIBS) \
+  $(VCONF_LIBS) \
+  libdali-adaptor.la \
+  $(HARFBUZZ_LIBS) \
+  -L${prefix}/lib
diff --git a/build/tizen/adaptor/dali-adaptor-integration.pc.in b/build/tizen/adaptor/dali-adaptor-integration.pc.in
new file mode 100644 (file)
index 0000000..95a89a6
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+apiversion=@DALI_ADAPTOR_VERSION@
+libdir=@libdir@
+includedir=@devincludepath@
+
+Name: Samsung OpenGLES Adaptor Integration
+Description: Adaptor integration layer for 3D Canvas using OpenGLES
+Version: ${apiversion}
+Requires: dali
+Libs: -L${libdir}
+Cflags: -I${includedir}/dali/public-api/adaptor-framework/ -I${includedir}/dali/devel-api/adaptor-framework/ -I${includedir}/dali/integration-api/adaptors/
diff --git a/build/tizen/adaptor/linker-test.cpp b/build/tizen/adaptor/linker-test.cpp
new file mode 100644 (file)
index 0000000..d2727d7
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/dali-core.h>
+
+#include <application.h>
+#include <adaptor.h>
+#include <render-surface.h>
+#include <orientation.h>
+#include <timer.h>
+#include <iostream>
+
+using namespace Dali;
+
+/*****************************************************************************
+ * Test to see if the dali-adaptor is linking correctly.
+ */
+
+class LinkerApp : public ConnectionTracker
+{
+public:
+  LinkerApp(Application &app)
+  {
+    app.InitSignal().Connect(this, &LinkerApp::Create);
+  }
+
+public:
+
+  void Create(Application& app)
+  {
+  }
+};
+
+/*****************************************************************************/
+
+int
+main(int argc, char **argv)
+{
+  try
+  {
+    Application app = Application::New(&argc, &argv);
+
+    LinkerApp linkerApp (app);
+    app.MainLoop();
+  }
+  catch(...)
+  {
+    std::cout << "Exception caught";
+  }
+
+  return 0;
+}
diff --git a/build/tizen/configure.ac b/build/tizen/configure.ac
new file mode 100644 (file)
index 0000000..d0f7c95
--- /dev/null
@@ -0,0 +1,305 @@
+#
+# Copyright (c) 2015 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+m4_define([dali_version],[0.1.0])
+AC_INIT([dali], [dali_version])
+AM_INIT_AUTOMAKE([-Wall foreign])
+
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+AC_PROG_MKDIR_P
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+LT_INIT
+
+DALI_ADAPTOR_VERSION=dali_version
+AC_SUBST(DALI_ADAPTOR_VERSION)
+
+FREETYPE_REQUIRED=9.16.3
+
+PKG_CHECK_MODULES(DALICORE, dali-core)
+PKG_CHECK_MODULES(ELEMENTARY, elementary)
+PKG_CHECK_MODULES(ECORE, ecore)
+PKG_CHECK_MODULES(ECORE_IPC, ecore-ipc)
+PKG_CHECK_MODULES(EXIF, libexif)
+PKG_CHECK_MODULES(FREETYPE, [freetype2 >= $FREETYPE_REQUIRED])
+PKG_CHECK_MODULES(FONTCONFIG, fontconfig)
+PKG_CHECK_MODULES(PNG, libpng)
+PKG_CHECK_MODULES(LIBEXIF, libexif)
+PKG_CHECK_MODULES(LIBDRM, libdrm)
+PKG_CHECK_MODULES(LIBCURL, libcurl)
+PKG_CHECK_MODULES(HARFBUZZ, harfbuzz)
+PKG_CHECK_MODULES(FRIBIDI, fribidi)
+PKG_CHECK_MODULES(TTRACE,  ttrace, AC_DEFINE(ENABLE_TTRACE, 1, [ttrace available]),
+                  [ AC_MSG_NOTICE([Tizen Trace not avaiable]) ]
+                  )
+
+# Check for EldBus.h in ECore
+#PKG_CHECK_MODULES(ELDBUS, eldbus, [ eldbus_available=yes ],  [ eldbus_available=no ] )
+eldbus_available=no
+
+DALI_ELDBUS_AVAILABLE=
+if test "x$eldbus_available" = "xyes"; then
+  DALI_ELDBUS_AVAILABLE=true
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DDALI_ELDBUS_AVAILABLE "
+fi
+AC_SUBST(DALI_ELDBUS_AVAILABLE)
+
+
+AC_ARG_ENABLE([feedback],
+              [AC_HELP_STRING([ --enable-feedback],
+                              [Enable feedback plugin])],
+              [enable_feedback=yes],
+              [enable_feedback=no])
+
+AM_CONDITIONAL([USE_FEEDBACK], [test x$enable_feedback = xyes])
+
+DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DPLATFORM_TIZEN"
+
+AC_ARG_ENABLE(exportall,
+              [AC_HELP_STRING([--enable-exportall],
+                              [enables the exporting of all the symbols in the library])],
+              [enable_exportall=yes],
+              [enable_exportall=no])
+
+AC_ARG_ENABLE([debug],
+              [AC_HELP_STRING([--enable-debug],
+                              [Turns on debugging])],
+              [enable_debug=$enableval],
+              [enable_debug=no])
+
+AC_ARG_ENABLE(shaderbincache,
+              [AC_HELP_STRING([--enable-shaderbincache],
+                              [enables shader binary cache])],
+              [enable_shaderbincache=$enableval],
+              [enable_shaderbincache=DISABLE])
+
+AC_ARG_ENABLE(network,
+              [AC_HELP_STRING([--enable-network],
+                              [enables network for debug tool])],
+              [enable_network=$enableval],
+              [enable_network=no])
+
+
+if test "x$enable_debug" = "xyes"; then
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DDEBUG_ENABLED"
+fi
+
+if test "x$enable_debug" = "xno" -a "x$enable_exportall" = "xno"; then
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -fvisibility=hidden -DHIDE_DALI_INTERNALS"
+fi
+
+if test "x$enable_shaderbincache" = "xENABLE"; then
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DSHADERBIN_CACHE_ENABLED"
+fi
+
+if test "x$enable_network" = "xyes"; then
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DNETWORK_ENABLED"
+fi
+
+AC_ARG_ENABLE([gles],
+              [AC_HELP_STRING([--enable-gles],
+                              [Specify the OpenGL ES version for backwards compatibility])],
+              [enable_gles=$enableval],
+              [enable_gles=30])
+
+DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DDALI_GLES_VERSION=${enable_gles}"
+
+# node.js by default statically links against libuv, so it doesn't need to install
+# a libuv headers/ shared library. So we can't use pkg-config to access any headers.
+# As a work around we pass the node deps path so we can access the libuv headers inside nodes
+# directory
+AC_ARG_WITH([node-js],
+              [AC_HELP_STRING([--with-node-js],
+                              [Node.JS path that contains Lib UV headers. Setting this configures DALi to work with LibUV mainloop used in Node.JS.
+                              For example /usr/tmp/downloads/node-v0.12.4/deps/uv/include/ ])],
+              [with_node_js=$withval],
+              [with_node_js=no])
+
+# Node.JS already has a libuv main loop running,so we have to integrate with it
+AM_CONDITIONAL(LIB_UV_EVENT_LOOP, test x$with_node_js != xno)
+
+
+build_for_node_js=no
+if test "x$with_node_js" != "xno"; then
+  AC_MSG_NOTICE("build for node_js == yes");
+  [build_for_node_js=yes]
+  DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DNODE_JS_SUPPORT  -I${with_node_js}"
+else
+ #not using node.js build
+  AC_MSG_NOTICE("build for node_js == no");
+fi
+
+
+AC_ARG_WITH([over-tizen_2_2],
+            [AC_HELP_STRING([--with-over-tizen_2_2],
+                            [Use tizen API over ver. 2.2])],
+            [with_over_tizen_2_2=yes],
+            [with_over_tizen_2_2=no])
+
+# Tizen Profile options
+AC_ARG_ENABLE([profile],
+              [AC_HELP_STRING([--enable-profile=COMMON,MOBILE,WEARABLE,TV,UBUNTU],
+                            [Select the variant of tizen])],
+              [enable_profile=$enableval],
+              [enable_profile=COMMON])
+
+# Ensure valid profile selected
+if test "x$enable_profile" != "xCOMMON" -a "x$enable_profile" != "xMOBILE" -a "x$enable_profile" != "xWEARABLE" -a "x$enable_profile" != "xTV" -a "x$enable_profile" != "xUBUNTU"; then
+  AC_MSG_ERROR([$enable_profile is an invalid profile])
+fi
+
+AC_ARG_ENABLE(wayland,
+              [  --enable-wayland       Build on Wayland],
+              enable_wayland=yes,
+              enable_wayland=no)
+
+DALI_ADAPTOR_CFLAGS="$DALI_ADAPTOR_CFLAGS -DDALI_PROFILE_${enable_profile}"
+DALI_PROFILE_CFLAGS=" -DDALI_PROFILE_${enable_profile}"
+AM_CONDITIONAL([COMMON_PROFILE], [test x$enable_profile = xCOMMON])
+AM_CONDITIONAL([MOBILE_PROFILE], [test x$enable_profile = xMOBILE])
+AM_CONDITIONAL([WEARABLE_PROFILE], [test x$enable_profile = xWEARABLE])
+AM_CONDITIONAL([TV_PROFILE], [test x$enable_profile = xTV])
+AM_CONDITIONAL([UBUNTU_PROFILE], [test x$enable_profile = xUBUNTU])
+AM_CONDITIONAL([WAYLAND], [test x$enable_wayland = xyes])
+
+AM_CONDITIONAL([ENABLE_NETWORK], [test x$enable_network = xyes])
+
+# Platforms should either enable features or remove them, they
+# should not disable features. This allows the developer to override
+# features through the command line.
+
+if test "x$enable_profile" = "xMOBILE"; then
+enable_assimp=no
+fi
+
+if test "x$enable_profile" = "xUBUNTU"; then
+PKG_CHECK_MODULES(OPENGLES20, glesv2 egl)
+else
+PKG_CHECK_MODULES(OPENGLES20, gles20)
+PKG_CHECK_MODULES(CAPI_APPFW_APPLICATION, capi-appfw-application)
+PKG_CHECK_MODULES(DLOG, dlog)
+PKG_CHECK_MODULES(SENSOR, sensor)
+PKG_CHECK_MODULES(TTS, tts)
+PKG_CHECK_MODULES(VCONF, vconf)
+PKG_CHECK_MODULES(CAPI_SYSTEM_SYSTEM_SETTINGS, capi-system-system-settings)
+
+if test "x$enable_wayland" != "xyes"; then
+PKG_CHECK_MODULES(UTILX, utilX)
+fi
+
+if test "x$with_over_tizen_2_2" = "xyes"; then
+PKG_CHECK_MODULES(CAPI_SYSTEM_INFO, capi-system-info)
+fi
+
+fi # ubuntu profile test
+
+if test "x$enable_wayland" = "xyes"; then
+PKG_CHECK_MODULES(WAYLAND, [ecore-wayland egl wayland-egl wayland-client >= 1.2.0 xkbcommon],
+                  [DALI_HAS_ECOREWL=yes],
+                  [DALI_HAS_ECOREWL=no])
+else
+PKG_CHECK_MODULES(ECORE_X, [ecore-x],
+                  [DALI_HAS_ECOREX=yes],
+                  [DALI_HAS_ECOREX=no])
+PKG_CHECK_MODULES(X11, [x11],
+                  [DALI_HAS_X11=yes],
+                  [DALI_HAS_X11=no])
+fi
+
+if test "x$enable_feedback" = "xyes"; then
+
+if test "x$enable_profile" = "xCOMMON" || test "x$enable_profile" = "xTV"; then
+PKG_CHECK_MODULES(HAPTIC, haptic)
+fi
+
+if test "x$enable_profile" = "xMOBILE"; then
+PKG_CHECK_MODULES(DEVICED, deviced)
+fi
+
+PKG_CHECK_MODULES(FEEDBACK, feedback)
+PKG_CHECK_MODULES(MMFSOUND, mm-sound)
+fi
+
+if test x$DALI_DATA_RW_DIR != x; then
+  dataReadWriteDir=$DALI_DATA_RW_DIR
+else
+  dataReadWriteDir=${prefix}/share/dali/
+fi
+
+if test x$DALI_DATA_RO_DIR != x; then
+  dataReadOnlyDir=$DALI_DATA_RO_DIR
+else
+  dataReadOnlyDir=${prefix}/share/dali/
+fi
+
+if test x$FONT_CONFIGURATION_FILE != x; then
+  fontConfigurationFile=$FONT_CONFIGURATION_FILE
+fi
+
+AC_SUBST(dataReadWriteDir)
+AC_SUBST(dataReadOnlyDir)
+AC_SUBST(DALI_ADAPTOR_CFLAGS)
+AC_SUBST(DALI_PROFILE_CFLAGS)
+AC_SUBST(fontConfigurationFile)
+
+
+# Specify the include directory for development headers
+#devincludepath=${includedir}/dali/internal
+devincludepath=${includedir}
+AC_SUBST(devincludepath)
+
+AC_CONFIG_FILES([
+ Makefile
+ adaptor/Makefile
+ dali.pc
+ adaptor/dali-adaptor-integration.pc
+])
+
+AM_CONDITIONAL([USE_PLUGIN], [test x$enable_feedback = xyes || test x$enable_bullet = xyes])
+
+if test "x$enable_feedback" = "xyes" || test "x$enable_bullet" = "xyes"; then
+AC_CONFIG_FILES([
+ plugins/Makefile
+])
+fi
+
+AC_OUTPUT
+
+
+echo "
+Configuration
+-------------
+  Prefix:                           $prefix
+  Debug Build:                      $enable_debug
+  Compile flags                     $DALI_ADAPTOR_CFLAGS
+  Profile:                          $enable_profile
+  Data Dir (Read/Write):            $dataReadWriteDir
+  Data Dir (Read Only):             $dataReadOnlyDir
+  OVERTIZEN2.2:                     $with_over_tizen_2_2
+  EldBus:                           $eldbus_available
+  Shader Binary Cache:              $enable_shaderbincache
+  Build for Node.JS (LibUV)         $build_for_node_js
+  Network enabled:                  $enable_network
+  Font config file:                 $fontConfigurationFile
+"
+# optional output of node.js source path if we're building for node.js
+if test "x$build_for_node_js" != "xno"; then
+echo "  Node.JS LibUV header path         $with_node_js"
+fi
diff --git a/build/tizen/dali.pc.in b/build/tizen/dali.pc.in
new file mode 100644 (file)
index 0000000..94a095e
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+apiversion=@DALI_ADAPTOR_VERSION@
+libdir=@libdir@
+includedir=@devincludepath@
+
+Name: Samsung OpenGLES Toolkit Adaptor
+Description: 3D Canvas Toolkit using OpenGLES (with the adaptor)
+Version: ${apiversion}
+Requires: dali-core
+Libs: -L${libdir} -ldali-adaptor
+Cflags: -I${includedir}/dali
diff --git a/build/tizen/plugins/Makefile.am b/build/tizen/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..e6c6692
--- /dev/null
@@ -0,0 +1,90 @@
+#
+# Copyright (c) 2015 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Build the Dali feedback plugin
+
+plugin_src_dir = ../../../plugins
+
+include ../../../plugins/sounds/file.list
+include ../../../plugins/file.list
+
+plugin_sounds_dir = ../../../plugins/sounds
+
+lib_LTLIBRARIES =
+
+if USE_FEEDBACK
+lib_LTLIBRARIES += libdali-feedback-plugin.la
+endif
+
+if USE_FEEDBACK
+dalisounddir = ${dataReadOnlyDir}/plugins/sounds/
+dalisound_DATA = ${dali_plugin_sound_files}
+
+# Feedback
+libdali_feedback_plugin_la_SOURCES = \
+                     $(plugin_src_files)
+
+libdali_feedback_plugin_la_DEPENDENCIES =
+
+libdali_feedback_plugin_la_CXXFLAGS = -DDALI_COMPILATION \
+                      -DDALI_SOUND_DIR="\"${dalisounddir}\"" \
+                      $(DLOG_CFLAGS) \
+                      $(DALICORE_CFLAGS) \
+                      $(MMFSOUND_CFLAGS) \
+                      $(FEEDBACK_CFLAGS) \
+                      $(DALI_PROFILE_CFLAGS) \
+                      $(DALI_ADAPTOR_CFLAGS) \
+                      -I../../../adaptors/public-api \
+                      -I../../../adaptors/integration-api \
+                      -I../../../adaptors/public-api/adaptor-framework \
+                      -I../../../adaptors/devel-api/adaptor-framework \
+                      -Werror -Wall
+
+libdali_feedback_plugin_la_LIBADD = \
+                      $(DLOG_LIBS) \
+                      $(MMFSOUND_LIBS)
+
+libdali_feedback_plugin_la_LDFLAGS = \
+                      -rdynamic
+
+if MOBILE_PROFILE
+libdali_feedback_plugin_la_CXXFLAGS += \
+                      $(DEVICED_CFLAGS)
+
+libdali_feedback_plugin_la_LIBADD += \
+                      $(DEVICED_LIBS)
+endif
+
+if TV_PROFILE
+libdali_feedback_plugin_la_CXXFLAGS += \
+                      $(HAPTIC_CFLAGS)
+
+libdali_feedback_plugin_la_LIBADD += \
+                      $(HAPTIC_LIBS)
+endif
+
+if COMMON_PROFILE
+libdali_feedback_plugin_la_CXXFLAGS += \
+                      $(HAPTIC_CFLAGS)
+
+libdali_feedback_plugin_la_LIBADD += \
+                      $(HAPTIC_LIBS)
+endif
+
+libdali_feedback_plugin_la_LIBADD += \
+                      $(FEEDBACK_LIBS)
+
+endif
diff --git a/dali-adaptor.manifest b/dali-adaptor.manifest
new file mode 100644 (file)
index 0000000..2761524
--- /dev/null
@@ -0,0 +1,8 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+       <assign>
+               <filesystem path="/usr/bin/dalireslog.sh" exec_label="none"/>
+       </assign>
+</manifest>
diff --git a/doc/dali-adaptor_doc.h b/doc/dali-adaptor_doc.h
new file mode 100644 (file)
index 0000000..bbb5954
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef __DALI_ADAPTOR_DOC_H__
+#define __DALI_ADAPTOR_DOC_H__
+
+/**
+ * @defgroup dali_adaptor DALi Adaptor
+ *
+ * @brief This module is a platform adaptation layer. It initializes and sets up DALi appropriately.
+ * The module provides many platform-related services with its internal module,
+ * platform abstraction. Several signals can be connected to it to keep you informed when
+ * certain platform-related activities occur.
+ *
+ * @ingroup dali
+ * @{
+ *   @defgroup dali_adaptor_framework Adaptor Framework
+ *   @brief Classes for the adaption layer.
+ * @}
+ */
+
+#endif  /* __DALI_ADAPTOR_DOC_H__ */
diff --git a/packaging/dali-adaptor.spec b/packaging/dali-adaptor.spec
new file mode 100644 (file)
index 0000000..e01ba6f
--- /dev/null
@@ -0,0 +1,283 @@
+%bcond_with wayland
+
+Name:       dali-adaptor
+Summary:    The DALi Tizen Adaptor
+Version:    1.0.49
+Release:    1
+Group:      System/Libraries
+License:    Apache-2.0 and BSD-2.0 and MIT
+URL:        https://review.tizen.org/git/?p=platform/core/uifw/dali-adaptor.git;a=summary
+Source0:    %{name}-%{version}.tar.gz
+
+%define profile %{tizen_profile_name}
+
+%if "%{profile}" == "mobile"
+%define dali_profile MOBILE
+%define dali_feedback_plugin 1
+%define over_tizen_2_2 1
+%define shaderbincache_flag DISABLE
+%endif
+
+%if "%{profile}" == "tv"
+%define dali_profile TV
+%define dali_feedback_plugin 0
+%define over_tizen_2_2 1
+%define shaderbincache_flag ENABLE
+%endif
+
+%if "%{profile}" == "wearable"
+%define dali_profile WEARABLE
+%define dali_feedback_plugin 0
+%define over_tizen_2_2 1
+%define shaderbincache_flag DISABLE
+%endif
+
+%if "%{profile}" == "common"
+%define dali_profile COMMON
+%define dali_feedback_plugin 0
+%define over_tizen_2_2 0
+%define shaderbincache_flag DISABLE
+%endif
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires:       boost-thread
+Requires:       boost-chrono
+Requires:       giflib
+BuildRequires:  pkgconfig
+BuildRequires:  gawk
+BuildRequires:  pkgconfig(sensor)
+BuildRequires:  pkgconfig(aul)
+BuildRequires:  boost-devel
+BuildRequires:  giflib-devel
+BuildRequires:  pkgconfig(fontconfig)
+BuildRequires:  pkgconfig(elementary)
+BuildRequires:  pkgconfig(capi-appfw-application)
+BuildRequires:  libjpeg-turbo-devel
+BuildRequires:  pkgconfig(evas)
+BuildRequires:  dali-devel
+BuildRequires:  dali-integration-devel
+BuildRequires:  vconf-devel
+BuildRequires:  vconf-keys-devel
+BuildRequires:  tts-devel
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  libdrm-devel
+BuildRequires:  pkgconfig(libexif)
+BuildRequires:  pkgconfig(capi-system-system-settings)
+BuildRequires:  pkgconfig(libpng)
+BuildRequires:  libcurl-devel
+BuildRequires:  pkgconfig(gles20)
+
+%if 0%{?over_tizen_2_2}
+BuildRequires:  pkgconfig(capi-system-info)
+%endif
+
+%if %{with wayland}
+BuildRequires:  pkgconfig(ecore-wayland)
+BuildRequires:  pkgconfig(wayland-egl)
+BuildRequires:  pkgconfig(wayland-client)
+%else
+BuildRequires:  pkgconfig(xext)
+BuildRequires:  pkgconfig(xi)
+BuildRequires:  pkgconfig(xfixes)
+BuildRequires:  pkgconfig(xdamage)
+BuildRequires:  pkgconfig(utilX)
+%endif
+
+BuildRequires:  pkgconfig(harfbuzz)
+BuildRequires:  fribidi-devel
+
+%description
+The DALi Tizen Adaptor provides a Tizen specific implementation of the dali-core
+platform abstraction and application shell
+
+##############################
+# devel
+##############################
+%package devel
+Summary:    Development components for the DALi Tizen Adaptor
+Group:      Development/Building
+Requires:   %{name} = %{version}-%{release}
+Requires:   %{name}-integration-devel = %{version}-%{release}
+Requires:   boost-devel
+
+%description devel
+Development components for the DALi Tizen Adaptor - public headers and package configs
+
+##############################
+# integration-devel
+##############################
+%package integration-devel
+Summary:    Integration development package for the Adaptor
+Group:      Development/Building
+Requires:   %{name} = %{version}-%{release}
+
+%description integration-devel
+Integration development package for the Adaptor - headers for integrating with an adaptor library.
+
+##############################
+# Dali Feedback Plugin
+##############################
+%package dali-feedback-plugin
+Summary:    Plugin to play haptic and audio feedback for Dali
+Group:      System/Libraries
+%if 0%{?dali_feedback_plugin}
+#Requires:       libdeviced
+BuildRequires:  pkgconfig(mm-sound)
+BuildRequires:  pkgconfig(deviced)
+BuildRequires:  libfeedback-devel
+%endif
+
+%description dali-feedback-plugin
+Feedback plugin to play haptic and audio feedback for Dali
+
+##############################
+# Preparation
+##############################
+%prep
+%setup -q
+%define dali_data_rw_dir         /usr/share/dali/
+%define dali_data_ro_dir         /usr/share/dali/
+%define user_shader_cache_dir    %{dali_data_ro_dir}/core/shaderbin/
+%define font_preloaded_path      /usr/share/fonts/
+%define font_downloaded_path     /opt/share/fonts/
+%define font_application_path    /usr/share/app_fonts/
+%define font_configuration_file  /opt/etc/fonts/conf.avail/99-slp.conf
+%define dali_plugin_sound_files  %{dali_data_ro_dir}/plugins/sounds/
+
+%define dev_include_path %{_includedir}
+
+##############################
+# Build
+##############################
+%build
+PREFIX+="/usr"
+CXXFLAGS+=" -Wall -g -Os -fPIC -fvisibility-inlines-hidden -fdata-sections -ffunction-sections "
+LDFLAGS+=" -Wl,--rpath=%{_libdir} -Wl,--as-needed -Wl,--gc-sections -Wl,-Bsymbolic-functions "
+
+%ifarch %{arm}
+CXXFLAGS+=" -D_ARCH_ARM_ -lgcc"
+%endif
+
+%if %{with wayland}
+CFLAGS+=" -DWAYLAND"
+CXXFLAGS+=" -DWAYLAND"
+configure_flags="--enable-wayland"
+%endif
+
+%if 0%{?over_tizen_2_2}
+CFLAGS+=" -DOVER_TIZEN_SDK_2_2"
+CXXFLAGS+=" -DOVER_TIZEN_SDK_2_2"
+%endif
+
+libtoolize --force
+cd %{_builddir}/%{name}-%{version}/build/tizen
+autoreconf --install
+
+DALI_DATA_RW_DIR="%{dali_data_rw_dir}" ; export DALI_DATA_RW_DIR
+DALI_DATA_RO_DIR="%{dali_data_ro_dir}"  ; export DALI_DATA_RO_DIR
+FONT_PRELOADED_PATH="%{font_preloaded_path}" ; export FONT_PRELOADED_PATH
+FONT_DOWNLOADED_PATH="%{font_downloaded_path}" ; export FONT_DOWNLOADED_PATH
+FONT_APPLICATION_PATH="%{font_application_path}"  ; export FONT_APPLICATION_PATH
+FONT_CONFIGURATION_FILE="%{font_configuration_file}" ; export FONT_CONFIGURATION_FILE
+
+%configure --prefix=$PREFIX --with-jpeg-turbo --enable-gles=20 --enable-shaderbincache=%{shaderbincache_flag} --enable-profile=%{dali_profile} \
+%if 0%{?dali_feedback_plugin}
+           --enable-feedback \
+%endif
+%if 0%{?over_tizen_2_2}
+           --with-over-tizen_2_2 \
+%endif
+           $configure_flags --libdir=%{_libdir}
+
+make %{?jobs:-j%jobs}
+
+##############################
+# Installation
+##############################
+%install
+rm -rf %{buildroot}
+cd build/tizen
+%make_install DALI_DATA_RW_DIR="%{dali_data_rw_dir}" DALI_DATA_RO_DIR="%{dali_data_ro_dir}"
+
+# LICENSE
+mkdir -p %{buildroot}/usr/share/license
+cp -af %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/usr/share/license/%{name}
+
+##############################
+# Upgrade order:
+# 1 - Pre Install new package
+# 2 - Install new package
+# 3 - Post install new package
+# 4 - Pre uninstall old package
+# 5 - Remove files not overwritten by new package
+# 6 - Post uninstall old package
+##############################
+
+%pre
+exit 0
+
+##############################
+#  Post Install new package
+##############################
+%post
+/sbin/ldconfig
+exit 0
+
+%if 0%{?dali_feedback_plugin}
+%post dali-feedback-plugin
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+#   Pre Uninstall old package
+##############################
+%preun
+exit 0
+
+##############################
+#   Post Uninstall old package
+##############################
+%postun
+/sbin/ldconfig
+exit 0
+
+%if 0%{?dali_feedback_plugin}
+%postun dali-feedback-plugin
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# Files in Binary Packages
+##############################
+
+%files
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libdali-adap*.so*
+%defattr(-,app,app,-)
+%dir %{user_shader_cache_dir}
+%{_bindir}/*
+%{_datadir}/license/%{name}
+
+%files devel
+%defattr(-,root,root,-)
+%{dev_include_path}/dali/dali.h
+%{dev_include_path}/dali/public-api/*
+%{dev_include_path}/dali/devel-api/*
+%{_libdir}/pkgconfig/dali.pc
+
+%files integration-devel
+%defattr(-,root,root,-)
+%{dev_include_path}/dali/integration-api/adaptors/*
+%{_libdir}/pkgconfig/dali-adaptor-integration.pc
+
+%if 0%{?dali_feedback_plugin}
+%files dali-feedback-plugin
+%defattr(-,root,root,-)
+%{_libdir}/libdali-feedback-plugin.so*
+%{dali_plugin_sound_files}/*
+%endif
+
diff --git a/platform-abstractions/portable/atomics.h b/platform-abstractions/portable/atomics.h
new file mode 100644 (file)
index 0000000..bf5d8ce
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef _DALI_INTERNAL_PLATFORM_ATOMICS_H_
+#define _DALI_INTERNAL_PLATFORM_ATOMICS_H_
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * atomics.h
+ *
+ * Interface for atomic memory operations.
+ * There may be platform-specific versions of this file in other directories.
+ */
+
+namespace Dali
+{
+namespace Internal
+{
+
+/**
+ * @brief Atomic write to an aligned memory location in cacheable memory.
+ *
+ * For common platforms with coherent caches such as ARM mpcore and Intel CPUs,
+ * a cacheline can be in a writeable state in the L1 cache of exactly one core
+ * at a time. Therefore, a write to a location that does not require a read /
+ * modify / write cycle or cross a cacheline boundary is  automatically
+ * atomic.
+ *
+ * @param address A pointer to a location in a cacheable memory region that is
+ *        aligned to a 4 byte boundary.
+ * @param value A value to assign to the memory location in address.
+ */
+inline void AtomicWriteToCacheableAlignedAddress( volatile uint32_t * const address, const uint32_t value )
+{
+  DALI_ASSERT_DEBUG( ptrdiff_t(address) % 4 == 0 && "Address must be 32 bit aligned" );
+  *address = value;
+}
+
+/**
+ * @brief Atomic read from an aligned memory location in cacheable memory.
+ *
+ * For common platforms with coherent caches such as ARM mpcore and Intel CPUs,
+ * a cacheline can be in a writeable state in the L1 cache of exactly one core
+ * at a time. Therefore, a read a location that does not cross a cacheline
+ * boundary is automatically atomic.
+ *
+ * @param  address A pointer to a location in a cacheable memory region that is
+ *         aligned to a 4 byte boundary.
+ * @return The value stored at the memory location in address.
+ */
+inline uint32_t AtomicReadFromCacheableAlignedAddress( const volatile uint32_t * const address )
+{
+  DALI_ASSERT_DEBUG( ptrdiff_t(address) % 4 == 0 && "Address must be 32 bit aligned" );
+  return *address;
+}
+
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* _DALI_INTERNAL_PLATFORM_ATOMICS_H_ */
diff --git a/platform-abstractions/portable/file-closer.h b/platform-abstractions/portable/file-closer.h
new file mode 100644 (file)
index 0000000..bc4f362
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef _DALI_INTERNAL_PLATFORM_FILECLOSER_H__
+#define _DALI_INTERNAL_PLATFORM_FILECLOSER_H__
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+/**
+ * Opens files and closes them later even if an exception is thrown.
+ */
+class FileCloser
+{
+public:
+
+  /**
+   * @brief Construct a FileCloser guarding a new FILE* for accessing the path passed in.
+   */
+  FileCloser( const char * const filename, const char * const mode ) :
+    mFile(fopen(filename, mode))
+  {
+    DALI_ASSERT_DEBUG( filename != 0 && "Cant open a null filename." );
+    DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
+
+    if( mFile == 0 )
+    {
+      DALI_LOG_WARNING( "File open failed for: \"%s\" in mode: \"%s\".\n", filename, mode );
+    }
+  }
+
+  /**
+   * @brief Construct a FileCloser guarding a FILE* for reading out of the memory buffer passed in.
+   */
+  FileCloser( void * const buffer, const size_t bufferSize, const char * const mode ) :
+    mFile( fmemopen( buffer, bufferSize, mode ) )
+  {
+    DALI_ASSERT_DEBUG( buffer != 0 && "Cant open file on null buffer." );
+    DALI_ASSERT_DEBUG( bufferSize > 0 && "Pointless to open file on empty buffer." );
+    DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
+
+    if( mFile == 0 )
+    {
+      DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n", static_cast<void*>(buffer), static_cast<unsigned>(bufferSize), mode );
+    }
+  }
+
+   /**
+    * @brief Destroy the FileCloser and clean up its FILE*.
+    */
+  ~FileCloser()
+  {
+    if( mFile != 0 )
+    {
+      const int closeFailed = fclose( mFile );
+
+      if ( closeFailed )
+      {
+        DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>(mFile) );
+      }
+      mFile = 0;
+    }
+  }
+
+  /**
+   * @return The FILE* guarded by this object.
+   */
+  FILE* GetFile()
+  {
+    return mFile;
+  }
+
+private:
+
+  // Undefined
+  FileCloser( const FileCloser& fileCloser );
+
+  // Undefined
+  FileCloser& operator=( const FileCloser& fileCloser );
+
+private:
+  FILE* mFile;
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* _DALI_INTERNAL_PLATFORM_FILECLOSER_H__ */
diff --git a/platform-abstractions/portable/image-operations.cpp b/platform-abstractions/portable/image-operations.cpp
new file mode 100644 (file)
index 0000000..6a95969
--- /dev/null
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "image-operations.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <stddef.h>
+#include <cmath>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+namespace
+{
+
+using Integration::Bitmap;
+using Integration::BitmapPtr;
+typedef unsigned char PixelBuffer;
+
+/**
+ * @brief 4 byte pixel structure.
+ */
+struct Pixel4Bytes
+{
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+  uint8_t a;
+} __attribute__((packed, aligned(4))); //< Tell the compiler it is okay to use a single 32 bit load.
+
+/**
+ * @brief RGB888 pixel structure.
+ */
+struct Pixel3Bytes
+{
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+} __attribute__((packed, aligned(1)));
+
+/**
+ * @brief RGB565 pixel typedefed from a short.
+ *
+ * Access fields by manual shifting and masking.
+ */
+typedef uint16_t PixelRGB565;
+
+/**
+ * @brief a Pixel composed of two independent byte components.
+ */
+struct Pixel2Bytes
+{
+  uint8_t l;
+  uint8_t a;
+} __attribute__((packed, aligned(2))); //< Tell the compiler it is okay to use a single 16 bit load.
+
+
+#if defined(DEBUG_ENABLED)
+/**
+ * Disable logging of image operations or make it verbose from the commandline
+ * as follows (e.g., for dali demo app):
+ * <code>
+ * LOG_IMAGE_OPERATIONS=0 dali-demo #< off
+ * LOG_IMAGE_OPERATIONS=3 dali-demo #< on, verbose
+ * </code>
+ */
+Debug::Filter* gImageOpsLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_IMAGE_OPERATIONS" );
+#endif
+
+/** @return The greatest even number less than or equal to the argument. */
+inline unsigned int EvenDown( const unsigned int a )
+{
+  const unsigned int evened = a & ~1u;
+  return evened;
+}
+
+/**
+ * @brief Log bad parameters.
+ */
+void ValidateScalingParameters( const unsigned int inputWidth,
+                                const unsigned int inputHeight,
+                                const unsigned int desiredWidth,
+                                const unsigned int desiredHeight )
+{
+  if( desiredWidth > inputWidth || desiredHeight > inputHeight )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Upscaling not supported (%u, %u -> %u, %u).\n", inputWidth, inputHeight, desiredWidth, desiredHeight );
+  }
+
+  if( desiredWidth == 0u || desiredHeight == 0u )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Downscaling to a zero-area target is pointless." );
+  }
+
+  if( inputWidth == 0u || inputHeight == 0u )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Zero area images cannot be scaled" );
+  }
+}
+
+/**
+ * @brief Do debug assertions common to all scanline halving functions.
+ * @note Inline and in anon namespace so should boil away in release builds.
+ */
+inline void DebugAssertScanlineParameters( const uint8_t * const pixels, const unsigned int width )
+{
+  DALI_ASSERT_DEBUG( pixels && "Null pointer." );
+  DALI_ASSERT_DEBUG( width > 1u && "Can't average fewer than two pixels." );
+  DALI_ASSERT_DEBUG( width < 131072u && "Unusually wide image: are you sure you meant to pass that value in?" );
+}
+
+/**
+ * @brief Assertions on params to functions averaging pairs of scanlines.
+ * @note Inline as intended to boil away in release.
+ */
+inline void DebugAssertDualScanlineParameters( const uint8_t * const scanline1,
+                                               const uint8_t * const scanline2,
+                                               uint8_t* const outputScanline,
+                                               const size_t widthInComponents )
+{
+  DALI_ASSERT_DEBUG( scanline1 && "Null pointer." );
+  DALI_ASSERT_DEBUG( scanline2 && "Null pointer." );
+  DALI_ASSERT_DEBUG( outputScanline && "Null pointer." );
+  DALI_ASSERT_DEBUG( ((scanline1 >= scanline2 + widthInComponents) || (scanline2 >= scanline1 + widthInComponents )) && "Scanlines alias." );
+  DALI_ASSERT_DEBUG( ((((void*)outputScanline) >= (void*)(scanline2 + widthInComponents)) || (((void*)scanline2) >= (void*)(scanline1 + widthInComponents))) && "Scanline 2 aliases output." );
+}
+
+/**
+ * @brief Converts a scaling mode to the definition of which dimensions matter when box filtering as a part of that mode.
+ */
+BoxDimensionTest DimensionTestForScalingMode( FittingMode::Type fittingMode )
+{
+  BoxDimensionTest dimensionTest;
+  dimensionTest = BoxDimensionTestEither;
+
+  switch( fittingMode )
+  {
+    // Shrink to fit attempts to make one or zero dimensions smaller than the
+    // desired dimensions and one or two dimensions exactly the same as the desired
+    // ones, so as long as one dimension is larger than the desired size, box
+    // filtering can continue even if the second dimension is smaller than the
+    // desired dimensions:
+    case FittingMode::SHRINK_TO_FIT:
+    {
+      dimensionTest = BoxDimensionTestEither;
+      break;
+    }
+    // Scale to fill mode keeps both dimensions at least as large as desired:
+    case FittingMode::SCALE_TO_FILL:
+    {
+      dimensionTest = BoxDimensionTestBoth;
+      break;
+    }
+    // Y dimension is irrelevant when downscaling in FIT_WIDTH mode:
+    case FittingMode::FIT_WIDTH:
+    {
+      dimensionTest = BoxDimensionTestX;
+      break;
+    }
+    // X Dimension is ignored by definition in FIT_HEIGHT mode:
+    case FittingMode::FIT_HEIGHT:
+    {
+      dimensionTest = BoxDimensionTestY;
+      break;
+    }
+  }
+
+  return dimensionTest;
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting ShinkToFit scaling mode.
+ */
+ImageDimensions FitForShrinkToFit( ImageDimensions target, ImageDimensions source )
+{
+  // Scale the input by the least extreme of the two dimensions:
+  const float widthScale  = target.GetX() / float(source.GetX());
+  const float heightScale = target.GetY() / float(source.GetY());
+  const float scale = widthScale < heightScale ? widthScale : heightScale;
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting SCALE_TO_FILL scaling mode.
+ * @note An image scaled into the output dimensions will need either top and
+ * bottom or left and right to be cropped away unless the source was pre-cropped
+ * to match the destination aspect ratio.
+ */
+ImageDimensions FitForScaleToFill( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetX() > 0 && source.GetY() > 0  && "Zero-area rectangles should not be passed-in" );
+  // Scale the input by the least extreme of the two dimensions:
+  const float widthScale  = target.GetX() / float(source.GetX());
+  const float heightScale = target.GetY() / float(source.GetY());
+  const float scale = widthScale > heightScale ? widthScale : heightScale;
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting FIT_WIDTH scaling mode.
+ */
+ImageDimensions FitForFitWidth( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetX() > 0 && "Cant fit a zero-dimension rectangle." );
+  const float scale  = target.GetX() / float(source.GetX());
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+   return source;
+  }
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting FIT_HEIGHT scaling mode.
+ */
+ImageDimensions FitForFitHeight( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetY() > 0 && "Cant fit a zero-dimension rectangle." );
+  const float scale = target.GetY() / float(source.GetY());
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Generate the rectangle to use as the target of a pixel sampling pass
+ * (e.g., nearest or linear).
+ */
+ImageDimensions FitToScalingMode( ImageDimensions requestedSize, ImageDimensions sourceSize, FittingMode::Type fittingMode )
+{
+  ImageDimensions fitDimensions;
+  switch( fittingMode )
+  {
+    case FittingMode::SHRINK_TO_FIT:
+    {
+      fitDimensions = FitForShrinkToFit( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::SCALE_TO_FILL:
+    {
+      fitDimensions = FitForScaleToFill( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::FIT_WIDTH:
+    {
+      fitDimensions = FitForFitWidth( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::FIT_HEIGHT:
+    {
+      fitDimensions = FitForFitHeight( requestedSize, sourceSize );
+      break;
+    }
+  };
+
+  return fitDimensions;
+}
+
+/**
+ * @brief Construct a bitmap with format and dimensions requested.
+ */
+BitmapPtr MakeEmptyBitmap( Pixel::Format pixelFormat, unsigned int width, unsigned int height )
+{
+  DALI_ASSERT_DEBUG( Pixel::GetBytesPerPixel(pixelFormat) && "Compressed formats not supported." );
+
+  // Allocate a pixel buffer to hold the image passed in:
+  Integration::BitmapPtr newBitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+  newBitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, width, height, width, height );
+  return newBitmap;
+}
+
+/**
+ * @brief Construct a bitmap object from a copy of the pixel array passed in.
+ */
+BitmapPtr MakeBitmap( const uint8_t * const pixels, Pixel::Format pixelFormat, unsigned int width, unsigned int height )
+{
+  DALI_ASSERT_DEBUG( pixels && "Null bitmap buffer to copy." );
+
+  // Allocate a pixel buffer to hold the image passed in:
+  Integration::BitmapPtr newBitmap = MakeEmptyBitmap( pixelFormat, width, height );
+
+  // Copy over the pixels from the downscaled image that was generated in-place in the pixel buffer of the input bitmap:
+  memcpy( newBitmap->GetBuffer(), pixels, width * height * Pixel::GetBytesPerPixel( pixelFormat ) );
+  return newBitmap;
+}
+
+/**
+ * @brief Work out the desired width and height, accounting for zeros.
+ *
+ * @param[in] bitmapWidth Width of image before processing.
+ * @param[in] bitmapHeight Height of image before processing.
+ * @param[in] requestedWidth Width of area to scale image into. Can be zero.
+ * @param[in] requestedHeight Height of area to scale image into. Can be zero.
+ * @return Dimensions of area to scale image into after special rules are applied.
+ */
+ImageDimensions CalculateDesiredDimensions( unsigned int bitmapWidth, unsigned int bitmapHeight, unsigned int requestedWidth, unsigned int requestedHeight )
+{
+  // If no dimensions have been requested, default to the source ones:
+  if( requestedWidth == 0 && requestedHeight == 0 )
+  {
+    return ImageDimensions( bitmapWidth, bitmapHeight );
+  }
+
+  // If both dimensions have values requested, use them both:
+  if( requestedWidth != 0 && requestedHeight != 0 )
+  {
+    return ImageDimensions( requestedWidth, requestedHeight );
+  }
+
+  // Only one of the dimensions has been requested. Calculate the other from
+  // the requested one and the source image aspect ratio:
+  if( requestedWidth != 0 )
+  {
+    return ImageDimensions( requestedWidth, bitmapHeight / float(bitmapWidth) * requestedWidth + 0.5f );
+  }
+  return ImageDimensions( bitmapWidth / float(bitmapHeight) * requestedHeight + 0.5f, requestedHeight );
+}
+
+} // namespace - unnamed
+
+ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions )
+{
+  return CalculateDesiredDimensions( rawDimensions.GetWidth(), rawDimensions.GetHeight(), requestedDimensions.GetWidth(), requestedDimensions.GetHeight() ) ;
+}
+
+/**
+ * @brief Implement ScaleTofill scaling mode cropping.
+ *
+ * Implement the cropping required for SCALE_TO_FILL mode,
+ * returning a new bitmap with the aspect ratio specified by the scaling mode.
+ * This scaling mode selects the central portion of a source image so any spare
+ * pixels off one of either the top or bottom edge need to be removed.
+ *
+ * @note If the input bitmap was not previously downscaled to exactly encompass
+ * the desired output size, the resulting bitmap will have the correct aspect
+ * ratio but will have larger dimensions than requested. This can be used to
+ * fake the scaling mode by relying on the GPU scaling at render time.
+ * If the input bitmap was previously maximally downscaled using a
+ * repeated box filter, this is a reasonable approach.
+ *
+ * @return The bitmap passed in if no scaling is needed or possible, else a new,
+ * smaller bitmap with the cropping required for the scaling mode applied.
+ */
+Integration::BitmapPtr CropForScaleToFill( Integration::BitmapPtr bitmap, ImageDimensions desiredDimensions );
+
+BitmapPtr ApplyAttributesToBitmap( BitmapPtr bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode )
+{
+  if( bitmap )
+  {
+    // Calculate the desired box, accounting for a possible zero component:
+    const ImageDimensions desiredDimensions  = CalculateDesiredDimensions( bitmap->GetImageWidth(), bitmap->GetImageHeight(), dimensions.GetWidth(), dimensions.GetHeight() );
+
+    // If a different size than the raw one has been requested, resize the image
+    // maximally using a repeated box filter without making it smaller than the
+    // requested size in either dimension:
+    bitmap = DownscaleBitmap( *bitmap, desiredDimensions, fittingMode, samplingMode );
+
+    // Cut the bitmap according to the desired width and height so that the
+    // resulting bitmap has the same aspect ratio as the desired dimensions:
+    if( bitmap && bitmap->GetPackedPixelsProfile() && fittingMode == FittingMode::SCALE_TO_FILL )
+    {
+      bitmap = CropForScaleToFill( bitmap, desiredDimensions );
+    }
+
+    // Examine the image pixels remaining after cropping and scaling to see if all
+    // are opaque, allowing faster rendering, or some have non-1.0 alpha:
+    if( bitmap && bitmap->GetPackedPixelsProfile() && Pixel::HasAlpha( bitmap->GetPixelFormat() ) )
+    {
+      bitmap->GetPackedPixelsProfile()->TestForTransparency();
+    }
+  }
+
+  return bitmap;
+}
+
+BitmapPtr CropForScaleToFill( BitmapPtr bitmap, ImageDimensions desiredDimensions )
+{
+  const unsigned inputWidth = bitmap->GetImageWidth();
+  const unsigned inputHeight = bitmap->GetImageHeight();
+  const unsigned desiredWidth = desiredDimensions.GetWidth();
+  const unsigned desiredHeight = desiredDimensions.GetHeight();
+
+  if( desiredWidth < 1U || desiredHeight < 1U )
+  {
+    DALI_LOG_WARNING( "Image scaling aborted as desired dimensions too small (%u, %u)\n.", desiredWidth, desiredHeight );
+  }
+  else if( inputWidth != desiredWidth || inputHeight != desiredHeight )
+  {
+    const Vector2 desiredDims( desiredWidth, desiredHeight );
+
+    // Scale the desired rectangle back to fit inside the rectangle of the loaded bitmap:
+    // There are two candidates (scaled by x, and scaled by y) and we choose the smallest area one.
+    const float widthsRatio = inputWidth / float(desiredWidth);
+    const Vector2 scaledByWidth = desiredDims * widthsRatio;
+    const float heightsRatio = inputHeight / float(desiredHeight);
+    const Vector2 scaledByHeight = desiredDims * heightsRatio;
+    // Trim top and bottom if the area of the horizontally-fitted candidate is less, else trim the sides:
+    const bool trimTopAndBottom = scaledByWidth.width * scaledByWidth.height < scaledByHeight.width * scaledByHeight.height;
+    const Vector2 scaledDims = trimTopAndBottom ? scaledByWidth : scaledByHeight;
+
+    // Work out how many pixels to trim from top and bottom, and left and right:
+    // (We only ever do one dimension)
+    const unsigned scanlinesToTrim = trimTopAndBottom ? fabsf( (scaledDims.y - inputHeight) * 0.5f ) : 0;
+    const unsigned columnsToTrim = trimTopAndBottom ? 0 : fabsf( (scaledDims.x - inputWidth) * 0.5f );
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Debug::Concise, "Bitmap, desired(%f, %f), loaded(%u,%u), cut_target(%f, %f), trimmed(%u, %u), vertical = %s.\n", desiredDims.x, desiredDims.y, inputWidth, inputHeight, scaledDims.x, scaledDims.y, columnsToTrim, scanlinesToTrim, trimTopAndBottom ? "true" : "false" );
+
+    // Make a new bitmap with the central part of the loaded one if required:
+    if( scanlinesToTrim > 0 || columnsToTrim > 0 )
+    {
+      const unsigned newWidth = inputWidth - 2 * columnsToTrim;
+      const unsigned newHeight = inputHeight - 2 * scanlinesToTrim;
+      BitmapPtr croppedBitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_DISCARD );
+      Integration::Bitmap::PackedPixelsProfile * packedView = croppedBitmap->GetPackedPixelsProfile();
+      DALI_ASSERT_DEBUG( packedView );
+      const Pixel::Format pixelFormat = bitmap->GetPixelFormat();
+      packedView->ReserveBuffer( pixelFormat, newWidth, newHeight, newWidth, newHeight );
+
+      const unsigned bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+
+      const PixelBuffer * const srcPixels = bitmap->GetBuffer() + scanlinesToTrim * inputWidth * bytesPerPixel;
+      PixelBuffer * const destPixels = croppedBitmap->GetBuffer();
+      DALI_ASSERT_DEBUG( srcPixels && destPixels );
+
+      // Optimize to a single memcpy if the left and right edges don't need a crop, else copy a scanline at a time:
+      if( trimTopAndBottom )
+      {
+        memcpy( destPixels, srcPixels, newHeight * newWidth * bytesPerPixel );
+      }
+      else
+      {
+        for( unsigned y = 0; y < newHeight; ++y )
+        {
+          memcpy( &destPixels[y * newWidth * bytesPerPixel], &srcPixels[y * inputWidth * bytesPerPixel + columnsToTrim * bytesPerPixel], newWidth * bytesPerPixel );
+        }
+      }
+
+      // Overwrite the loaded bitmap with the cropped version:
+      bitmap = croppedBitmap;
+    }
+  }
+
+  return bitmap;
+}
+
+Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap,
+                                        ImageDimensions desired,
+                                        FittingMode::Type fittingMode,
+                                        SamplingMode::Type samplingMode )
+{
+  // Source dimensions as loaded from resources (e.g. filesystem):
+  const unsigned int bitmapWidth  = bitmap.GetImageWidth();
+  const unsigned int bitmapHeight = bitmap.GetImageHeight();
+  // Desired dimensions (the rectangle to fit the source image to):
+  const unsigned int desiredWidth = desired.GetWidth();
+  const unsigned int desiredHeight = desired.GetHeight();
+
+  BitmapPtr outputBitmap( &bitmap );
+
+  // If a different size than the raw one has been requested, resize the image:
+  if( bitmap.GetPackedPixelsProfile() &&
+      (desiredWidth > 0.0f) && (desiredHeight > 0.0f) &&
+      ((desiredWidth < bitmapWidth) || (desiredHeight < bitmapHeight)) )
+  {
+    const Pixel::Format pixelFormat = bitmap.GetPixelFormat();
+
+    // Do the fast power of 2 iterated box filter to get to roughly the right side if the filter mode requests that:
+    unsigned int shrunkWidth = -1, shrunkHeight = -1;
+    DownscaleInPlacePow2( bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight );
+
+    // Work out the dimensions of the downscaled bitmap, given the scaling mode and desired dimensions:
+    const ImageDimensions filteredDimensions = FitToScalingMode( ImageDimensions( desiredWidth, desiredHeight ), ImageDimensions( shrunkWidth, shrunkHeight ), fittingMode );
+    const unsigned int filteredWidth = filteredDimensions.GetWidth();
+    const unsigned int filteredHeight = filteredDimensions.GetHeight();
+
+    // Run a filter to scale down the bitmap if it needs it:
+    bool filtered = false;
+    if( filteredWidth < shrunkWidth || filteredHeight < shrunkHeight )
+    {
+      if( samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR ||
+          samplingMode == SamplingMode::NEAREST || samplingMode == SamplingMode::BOX_THEN_NEAREST )
+      {
+        outputBitmap = MakeEmptyBitmap( pixelFormat, filteredWidth, filteredHeight );
+        if( outputBitmap )
+        {
+          if( samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR )
+          {
+            LinearSample( bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), pixelFormat, outputBitmap->GetBuffer(), filteredDimensions );
+          }
+          else
+          {
+            PointSample( bitmap.GetBuffer(), shrunkWidth, shrunkHeight, pixelFormat, outputBitmap->GetBuffer(), filteredWidth, filteredHeight );
+          }
+          filtered = true;
+        }
+      }
+    }
+    // Copy out the 2^x downscaled, box-filtered pixels if no secondary filter (point or linear) was applied:
+    if( filtered == false && ( shrunkWidth < bitmapWidth || shrunkHeight < bitmapHeight ) )
+    {
+      outputBitmap = MakeBitmap( bitmap.GetBuffer(), pixelFormat, shrunkWidth, shrunkHeight );
+    }
+  }
+
+  return outputBitmap;
+}
+
+namespace
+{
+/**
+ * @brief Returns whether to keep box filtering based on whether downscaled dimensions will overshoot the desired ones aty the next step.
+ * @param test Which combination of the two dimensions matter for terminating the filtering.
+ * @param scaledWidth The width of the current downscaled image.
+ * @param scaledHeight The height of the current downscaled image.
+ * @param desiredWidth The target width for the downscaling.
+ * @param desiredHeight The target height for the downscaling.
+ */
+bool ContinueScaling( BoxDimensionTest test, unsigned int scaledWidth, unsigned int scaledHeight, unsigned int desiredWidth, unsigned int desiredHeight )
+{
+  bool keepScaling = false;
+  const unsigned int nextWidth = scaledWidth >> 1u;
+  const unsigned int nextHeight = scaledHeight >> 1u;
+
+  if( nextWidth >= 1u && nextHeight >= 1u )
+  {
+    switch( test )
+    {
+      case BoxDimensionTestEither:
+      {
+        keepScaling = nextWidth >= desiredWidth || nextHeight >= desiredHeight;
+        break;
+      }
+      case BoxDimensionTestBoth:
+      {
+        keepScaling = nextWidth >= desiredWidth && nextHeight >= desiredHeight;
+        break;
+      }
+      case BoxDimensionTestX:
+      {
+        keepScaling = nextWidth >= desiredWidth;
+        break;
+      }
+      case BoxDimensionTestY:
+      {
+        keepScaling = nextHeight >= desiredHeight;
+        break;
+      }
+    }
+  }
+
+  return keepScaling;
+}
+
+/**
+ * @brief A shared implementation of the overall iterative box filter
+ * downscaling algorithm.
+ *
+ * Specialise this for particular pixel formats by supplying the number of bytes
+ * per pixel and two functions: one for averaging pairs of neighbouring pixels
+ * on a single scanline, and a second for averaging pixels at corresponding
+ * positions on different scanlines.
+ **/
+template<
+  int BYTES_PER_PIXEL,
+  void (*HalveScanlineInPlace)( unsigned char * const pixels, const unsigned int width ),
+  void (*AverageScanlines) ( const unsigned char * const scanline1, const unsigned char * const __restrict__ scanline2, unsigned char* const outputScanline, const unsigned int width )
+>
+void DownscaleInPlacePow2Generic( unsigned char * const pixels,
+                                  const unsigned int inputWidth,
+                                  const unsigned int inputHeight,
+                                  const unsigned int desiredWidth,
+                                  const unsigned int desiredHeight,
+                                  BoxDimensionTest dimensionTest,
+                                  unsigned& outWidth,
+                                  unsigned& outHeight )
+{
+  if( pixels == 0 )
+  {
+    return;
+  }
+  ValidateScalingParameters( inputWidth, inputHeight, desiredWidth, desiredHeight );
+
+  // Scale the image until it would be smaller than desired, stopping if the
+  // resulting height or width would be less than 1:
+  unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight;
+  while( ContinueScaling( dimensionTest, scaledWidth, scaledHeight, desiredWidth, desiredHeight ) )
+  {
+    const unsigned int lastWidth = scaledWidth;
+    scaledWidth  >>= 1u;
+    scaledHeight >>= 1u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Scaling to %u\t%u.\n", scaledWidth, scaledHeight );
+
+    const unsigned int lastScanlinePair = scaledHeight - 1;
+
+    // Scale pairs of scanlines until any spare one at the end is dropped:
+    for( unsigned int y = 0; y <= lastScanlinePair; ++y )
+    {
+      // Scale two scanlines horizontally:
+      HalveScanlineInPlace( &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], lastWidth );
+      HalveScanlineInPlace( &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], lastWidth );
+
+      // Scale vertical pairs of pixels while the last two scanlines are still warm in
+      // the CPU cache(s):
+      // Note, better access patterns for cache-coherence are possible for very large
+      // images but even a 4k wide RGB888 image will use just 24kB of cache (4k pixels
+      // * 3 Bpp * 2 scanlines) for two scanlines on the first iteration.
+      AverageScanlines(
+          &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL],
+          &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL],
+          &pixels[y * scaledWidth * BYTES_PER_PIXEL],
+          scaledWidth );
+    }
+  }
+
+  ///@note: we could finish off with one of two mutually exclusive passes, one squashing horizontally as far as possible, and the other vertically, if we knew a following cpu point or bilinear filter would restore the desired aspect ratio.
+  outWidth = scaledWidth;
+  outHeight = scaledHeight;
+}
+
+}
+
+void HalveScanlineInPlaceRGB888( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c11 = pixels[pixel * 3];
+    const unsigned int c12 = pixels[pixel * 3 + 1];
+    const unsigned int c13 = pixels[pixel * 3 + 2];
+    const unsigned int c21 = pixels[pixel * 3 + 3];
+    const unsigned int c22 = pixels[pixel * 3 + 4];
+    const unsigned int c23 = pixels[pixel * 3 + 5];
+
+    // Save the averaged byte pixel components:
+    pixels[outPixel * 3]     = AverageComponent( c11, c21 );
+    pixels[outPixel * 3 + 1] = AverageComponent( c12, c22 );
+    pixels[outPixel * 3 + 2] = AverageComponent( c13, c23 );
+  }
+}
+
+void HalveScanlineInPlaceRGBA8888( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+
+  uint32_t* const alignedPixels = reinterpret_cast<uint32_t*>(pixels);
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    const uint32_t averaged = AveragePixelRGBA8888( alignedPixels[pixel], alignedPixels[pixel + 1] );
+    alignedPixels[outPixel] = averaged;
+  }
+}
+
+void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+
+  uint16_t* const alignedPixels = reinterpret_cast<uint16_t*>(pixels);
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    const uint32_t averaged = AveragePixelRGB565( alignedPixels[pixel], alignedPixels[pixel + 1] );
+    alignedPixels[outPixel] = averaged;
+  }
+}
+
+void HalveScanlineInPlace2Bytes( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c11 = pixels[pixel * 2];
+    const unsigned int c12 = pixels[pixel * 2 + 1];
+    const unsigned int c21 = pixels[pixel * 2 + 2];
+    const unsigned int c22 = pixels[pixel * 2 + 3];
+
+    // Save the averaged byte pixel components:
+    pixels[outPixel * 2]     = AverageComponent( c11, c21 );
+    pixels[outPixel * 2 + 1] = AverageComponent( c12, c22 );
+  }
+}
+
+void HalveScanlineInPlace1Byte( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c1 = pixels[pixel];
+    const unsigned int c2 = pixels[pixel + 1];
+
+    // Save the averaged byte pixel component:
+    pixels[outPixel] = AverageComponent( c1, c2 );
+  }
+}
+
+/**
+ * @ToDo: Optimise for ARM using a 4 bytes at a time loop wrapped around the single ARMV6 instruction: UHADD8  R4, R0, R5. Note, this is not neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro, or extra power for clocking-up the idle copro.
+ * if (widthInComponents >= 7) { word32* aligned1 = scanline1 + 3 & 3; word32* aligned1_end = scanline1 + widthInPixels & 3; while(aligned1 < aligned1_end) { UHADD8  *aligned1++, *aligned2++, *alignedoutput++ } .. + 0 to 3 spare pixels at each end.
+ */
+void AverageScanlines1( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width );
+
+  for( unsigned int component = 0; component < width; ++component )
+  {
+    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+  }
+}
+
+void AverageScanlines2( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 2 );
+
+  for( unsigned int component = 0; component < width * 2; ++component )
+  {
+    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+  }
+}
+
+void AverageScanlines3( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 3 );
+
+  for( unsigned int component = 0; component < width * 3; ++component )
+  {
+    outputScanline[component] = AverageComponent( scanline1[component], scanline2[component] );
+  }
+}
+
+void AverageScanlinesRGBA8888( const unsigned char * const scanline1,
+                               const unsigned char * const __restrict__ scanline2,
+                               unsigned char * const outputScanline,
+                               const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 4 );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline1) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline2) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(outputScanline) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+
+  const uint32_t* const alignedScanline1 = reinterpret_cast<const uint32_t*>(scanline1);
+  const uint32_t* const alignedScanline2 = reinterpret_cast<const uint32_t*>(scanline2);
+  uint32_t* const alignedOutput = reinterpret_cast<uint32_t*>(outputScanline);
+
+  for( unsigned int pixel = 0; pixel < width; ++pixel )
+  {
+    alignedOutput[pixel] = AveragePixelRGBA8888( alignedScanline1[pixel], alignedScanline2[pixel] );
+  }
+}
+
+void AverageScanlinesRGB565( const unsigned char * const scanline1,
+                             const unsigned char * const __restrict__ scanline2,
+                             unsigned char * const outputScanline,
+                             const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 2 );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline1) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline2) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(outputScanline) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+
+  const uint16_t* const alignedScanline1 = reinterpret_cast<const uint16_t*>(scanline1);
+  const uint16_t* const alignedScanline2 = reinterpret_cast<const uint16_t*>(scanline2);
+  uint16_t* const alignedOutput = reinterpret_cast<uint16_t*>(outputScanline);
+
+  for( unsigned int pixel = 0; pixel < width; ++pixel )
+  {
+    alignedOutput[pixel] = AveragePixelRGB565( alignedScanline1[pixel], alignedScanline2[pixel] );
+  }
+}
+
+/// Dispatch to pixel format appropriate box filter downscaling functions.
+void DownscaleInPlacePow2( unsigned char * const pixels,
+                           Pixel::Format pixelFormat,
+                           unsigned int inputWidth,
+                           unsigned int inputHeight,
+                           unsigned int desiredWidth,
+                           unsigned int desiredHeight,
+                           FittingMode::Type fittingMode,
+                           SamplingMode::Type samplingMode,
+                           unsigned& outWidth,
+                           unsigned& outHeight )
+{
+  outWidth = inputWidth;
+  outHeight = inputHeight;
+  // Perform power of 2 iterated 4:1 box filtering if the requested filter mode requires it:
+  if( samplingMode == SamplingMode::BOX || samplingMode == SamplingMode::BOX_THEN_NEAREST || samplingMode == SamplingMode::BOX_THEN_LINEAR )
+  {
+    // Check the pixel format is one that is supported:
+    if( pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+    {
+      const BoxDimensionTest dimensionTest = DimensionTestForScalingMode( fittingMode );
+
+      if( pixelFormat == Pixel::RGBA8888 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGBA8888( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::RGB888 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGB888( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::RGB565 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGB565( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::LA88 )
+      {
+        Internal::Platform::DownscaleInPlacePow2ComponentPair( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::L8  || pixelFormat == Pixel::A8 )
+      {
+        Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else
+      {
+        DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not shrunk: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+void DownscaleInPlacePow2RGB888( unsigned char *pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned& outWidth,
+                                 unsigned& outHeight )
+{
+  DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight,
+                                   BoxDimensionTest dimensionTest,
+                                   unsigned& outWidth,
+                                   unsigned& outHeight )
+{
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2RGB565( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight )
+{
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
+ */
+void DownscaleInPlacePow2ComponentPair( unsigned char *pixels,
+                                        unsigned int inputWidth,
+                                        unsigned int inputHeight,
+                                        unsigned int desiredWidth,
+                                        unsigned int desiredHeight,
+                                        BoxDimensionTest dimensionTest,
+                                        unsigned& outWidth,
+                                        unsigned& outHeight )
+{
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
+                                             unsigned int inputWidth,
+                                             unsigned int inputHeight,
+                                             unsigned int desiredWidth,
+                                             unsigned int desiredHeight,
+                                             BoxDimensionTest dimensionTest,
+                                             unsigned int& outWidth,
+                                             unsigned int& outHeight )
+{
+  DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+namespace
+{
+
+/**
+ * @brief Point sample an image to a new resolution (like GL_NEAREST).
+ *
+ * Template is used purely as a type-safe code generator in this one
+ * compilation unit. Generated code is inlined into type-specific wrapper
+ * functions below which are exported to rest of module.
+ */
+template<typename PIXEL>
+inline void PointSampleAddressablePixels( const uint8_t * inPixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   uint8_t * outPixels,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight )
+{
+  DALI_ASSERT_DEBUG( ((desiredWidth <= inputWidth && desiredHeight <= inputHeight) ||
+      outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
+      "The input and output buffers must not overlap for an upscaling.");
+  DALI_ASSERT_DEBUG( ((uint64_t) inPixels)  % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+  DALI_ASSERT_DEBUG( ((uint64_t) outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const PIXEL* const inAligned = reinterpret_cast<const PIXEL*>(inPixels);
+  PIXEL* const       outAligned = reinterpret_cast<PIXEL*>(outPixels);
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  unsigned int inY = 0;
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    // Round fixed point y coordinate to nearest integer:
+    const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
+    const PIXEL* const inScanline = &inAligned[inputWidth * integerY];
+    PIXEL* const outScanline = &outAligned[desiredWidth * outY];
+
+    DALI_ASSERT_DEBUG( integerY < inputHeight );
+    DALI_ASSERT_DEBUG( reinterpret_cast<const uint8_t*>(inScanline) < ( inPixels + inputWidth * inputHeight * sizeof(PIXEL) ) );
+    DALI_ASSERT_DEBUG( reinterpret_cast<uint8_t*>(outScanline) < ( outPixels + desiredWidth * desiredHeight * sizeof(PIXEL) ) );
+
+    unsigned int inX = 0;
+    for( unsigned int outX = 0; outX < desiredWidth; ++outX )
+    {
+      // Round the fixed-point x coordinate to an integer:
+      const unsigned int integerX = (inX + (1u << 15u)) >> 16u;
+      const PIXEL* const inPixelAddress = &inScanline[integerX];
+      const PIXEL pixel = *inPixelAddress;
+      outScanline[outX] = pixel;
+      inX += deltaX;
+    }
+    inY += deltaY;
+  }
+}
+
+}
+
+// RGBA8888
+void PointSample4BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint32_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+// RGB565, LA88
+void PointSample2BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint16_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+// L8, A8
+void PointSample1BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint8_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+/* RGB888
+ * RGB888 is a special case as its pixels are not aligned addressable units.
+ */
+void PointSample3BPP( const uint8_t * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      uint8_t * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const unsigned int BYTES_PER_PIXEL = 3;
+
+  // Generate fixed-point 16.16 deltas in input image coordinates:
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  // Step through output image in whole integer pixel steps while tracking the
+  // corresponding locations in the input image using 16.16 fixed-point
+  // coordinates:
+  unsigned int inY = 0; //< 16.16 fixed-point input image y-coord.
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
+    const uint8_t* const inScanline = &inPixels[inputWidth * integerY * BYTES_PER_PIXEL];
+    uint8_t* const outScanline = &outPixels[desiredWidth * outY * BYTES_PER_PIXEL];
+    unsigned int inX = 0; //< 16.16 fixed-point input image x-coord.
+
+    for( unsigned int outX = 0; outX < desiredWidth * BYTES_PER_PIXEL; outX += BYTES_PER_PIXEL )
+    {
+      // Round the fixed-point input coordinate to the address of the input pixel to sample:
+      const unsigned int integerX = (inX + (1u << 15u)) >> 16u;
+      const uint8_t* const inPixelAddress = &inScanline[integerX * BYTES_PER_PIXEL];
+
+      // Issue loads for all pixel color components up-front:
+      const unsigned int c0 = inPixelAddress[0];
+      const unsigned int c1 = inPixelAddress[1];
+      const unsigned int c2 = inPixelAddress[2];
+      ///@ToDo: Optimise - Benchmark one 32bit load that will be unaligned 2/3 of the time + 3 rotate and masks, versus these three aligned byte loads, versus using an RGB packed, aligned(1) struct and letting compiler pick a strategy.
+
+      // Output the pixel components:
+      outScanline[outX]     = c0;
+      outScanline[outX + 1] = c1;
+      outScanline[outX + 2] = c2;
+
+      // Increment the fixed-point input coordinate:
+      inX += deltaX;
+    }
+
+    inY += deltaY;
+  }
+}
+
+// Dispatch to a format-appropriate point sampling function:
+void PointSample( const unsigned char * inPixels,
+                  unsigned int inputWidth,
+                  unsigned int inputHeight,
+                  Pixel::Format pixelFormat,
+                  unsigned char * outPixels,
+                  unsigned int desiredWidth,
+                  unsigned int desiredHeight )
+{
+  // Check the pixel format is one that is supported:
+  if( pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+  {
+    if( pixelFormat == Pixel::RGB888 )
+    {
+      PointSample3BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::RGBA8888 )
+    {
+      PointSample4BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 )
+    {
+      PointSample2BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::L8  || pixelFormat == Pixel::A8 )
+    {
+      PointSample1BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else
+    {
+      DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not point sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+// Linear sampling group below
+
+namespace
+{
+
+/** @brief Blend 4 pixels together using horizontal and vertical weights. */
+inline uint8_t BilinearFilter1BPPByte( uint8_t tl, uint8_t tr, uint8_t bl, uint8_t br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  return BilinearFilter1Component( tl, tr, bl, br, fractBlendHorizontal, fractBlendVertical );
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel2Bytes BilinearFilter2Bytes( Pixel2Bytes tl, Pixel2Bytes tr, Pixel2Bytes bl, Pixel2Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel2Bytes pixel;
+  pixel.l = BilinearFilter1Component( tl.l, tr.l, bl.l, br.l, fractBlendHorizontal, fractBlendVertical );
+  pixel.a = BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel3Bytes BilinearFilterRGB888( Pixel3Bytes tl, Pixel3Bytes tr, Pixel3Bytes bl, Pixel3Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel3Bytes pixel;
+  pixel.r = BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical );
+  pixel.g = BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical );
+  pixel.b = BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline PixelRGB565 BilinearFilterRGB565( PixelRGB565 tl, PixelRGB565 tr, PixelRGB565 bl, PixelRGB565 br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  const PixelRGB565 pixel = (BilinearFilter1Component( tl >> 11u, tr >> 11u, bl >> 11u, br >> 11u, fractBlendHorizontal, fractBlendVertical ) << 11u) +
+                            (BilinearFilter1Component( (tl >> 5u) & 63u, (tr >> 5u) & 63u, (bl >> 5u) & 63u, (br >> 5u) & 63u, fractBlendHorizontal, fractBlendVertical ) << 5u) +
+                             BilinearFilter1Component( tl & 31u, tr & 31u, bl & 31u, br & 31u, fractBlendHorizontal, fractBlendVertical );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel4Bytes BilinearFilter4Bytes( Pixel4Bytes tl, Pixel4Bytes tr, Pixel4Bytes bl, Pixel4Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel4Bytes pixel;
+  pixel.r = BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical );
+  pixel.g = BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical );
+  pixel.b = BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical );
+  pixel.a = BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical );
+  return pixel;
+}
+
+/**
+ * @brief Generic version of bilinear sampling image resize function.
+ * @note Limited to one compilation unit and exposed through type-specific
+ * wrapper functions below.
+ */
+template<
+  typename PIXEL,
+  PIXEL (*BilinearFilter) ( PIXEL tl, PIXEL tr, PIXEL bl, PIXEL br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical ),
+  bool DEBUG_ASSERT_ALIGNMENT
+>
+inline void LinearSampleGeneric( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  const unsigned int inputWidth = inputDimensions.GetWidth();
+  const unsigned int inputHeight = inputDimensions.GetHeight();
+  const unsigned int desiredWidth = desiredDimensions.GetWidth();
+  const unsigned int desiredHeight = desiredDimensions.GetHeight();
+
+  DALI_ASSERT_DEBUG( ((outPixels >= inPixels + inputWidth   * inputHeight   * sizeof(PIXEL)) ||
+                      (inPixels >= outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))) &&
+                     "Input and output buffers cannot overlap.");
+  if( DEBUG_ASSERT_ALIGNMENT )
+  {
+    DALI_ASSERT_DEBUG( ((uint64_t) inPixels)  % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+    DALI_ASSERT_DEBUG( ((uint64_t) outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+  }
+
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const PIXEL* const inAligned = reinterpret_cast<const PIXEL*>(inPixels);
+  PIXEL* const       outAligned = reinterpret_cast<PIXEL*>(outPixels);
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  unsigned int inY = 0;
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    PIXEL* const outScanline = &outAligned[desiredWidth * outY];
+
+    // Find the two scanlines to blend and the weight to blend with:
+    const unsigned int integerY1 = inY >> 16u;
+    const unsigned int integerY2 = integerY1 >= inputHeight ? integerY1 : integerY1 + 1;
+    const unsigned int inputYWeight = inY & 65535u;
+
+    DALI_ASSERT_DEBUG( integerY1 < inputHeight );
+    DALI_ASSERT_DEBUG( integerY2 < inputHeight );
+
+    const PIXEL* const inScanline1 = &inAligned[inputWidth * integerY1];
+    const PIXEL* const inScanline2 = &inAligned[inputWidth * integerY2];
+
+    unsigned int inX = 0;
+    for( unsigned int outX = 0; outX < desiredWidth; ++outX )
+    {
+      // Work out the two pixel scanline offsets for this cluster of four samples:
+      const unsigned int integerX1 = inX >> 16u;
+      const unsigned int integerX2 = integerX1 >= inputWidth ? integerX1 : integerX1 + 1;
+
+      // Execute the loads:
+      const PIXEL pixel1 = inScanline1[integerX1];
+      const PIXEL pixel2 = inScanline2[integerX1];
+      const PIXEL pixel3 = inScanline1[integerX2];
+      const PIXEL pixel4 = inScanline2[integerX2];
+      ///@ToDo Optimise - for 1 and 2  and 4 byte types to execute a single 2, 4, or 8 byte load per pair (caveat clamping) and let half of them be unaligned.
+
+      // Weighted bilinear filter:
+      const unsigned int inputXWeight = inX & 65535u;
+      outScanline[outX] = BilinearFilter( pixel1, pixel3, pixel2, pixel4, inputXWeight, inputYWeight );
+
+      inX += deltaX;
+    }
+    inY += deltaY;
+  }
+}
+
+}
+
+// Format-specific linear scaling instantiations:
+
+void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+// Dispatch to a format-appropriate linear sampling function:
+void LinearSample( const unsigned char * __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   Pixel::Format pixelFormat,
+                   unsigned char * __restrict__ outPixels,
+                   ImageDimensions outDimensions )
+{
+  // Check the pixel format is one that is supported:
+  if( pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::RGB565 )
+  {
+    if( pixelFormat == Pixel::RGB888 )
+    {
+      LinearSample3BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::RGBA8888 )
+    {
+      LinearSample4BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+    {
+      LinearSample1BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::LA88 )
+    {
+      LinearSample2BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if ( pixelFormat == Pixel::RGB565 )
+    {
+      LinearSampleRGB565( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else
+    {
+      DALI_ASSERT_DEBUG( false == "Inner branch conditions don't match outer branch." );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not linear sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
diff --git a/platform-abstractions/portable/image-operations.h b/platform-abstractions/portable/image-operations.h
new file mode 100644 (file)
index 0000000..2deb110
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
+#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/bitmap.h>
+#include <dali/public-api/images/image-operations.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+/**
+ * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
+ */
+enum BoxDimensionTest
+{
+  BoxDimensionTestEither,
+  BoxDimensionTestBoth,
+  BoxDimensionTestX,
+  BoxDimensionTestY
+};
+
+/**
+ * @brief The integer dimensions of an image or a region of an image packed into
+ *        16 bits per component.
+ * @note  This can only be used for images of up to 65535 x 65535 pixels.
+  */
+typedef Uint16Pair ImageDimensions;
+
+/**
+ * @brief Work out the true desired width and height, accounting for special
+ * rules for zeros in either or both input requested dimensions.
+ *
+ * @param[in] rawDimensions Width and height of image before processing.
+ * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
+ * @return Dimensions of area to scale image into after special rules are applied.
+ */
+ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
+
+/**
+ * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
+ * @{
+ */
+
+/**
+ * @brief Apply requested attributes to bitmap.
+ *
+ * This is the top-level function which runs the on-load image post-processing
+ * pipeline. Bitmaps enter here as loaded from the file system by the file
+ * loaders and leave downscaled and filtered as requested by the application,
+ * ready for use.
+ *
+ * @param[in] bitmap The input bitmap.
+ * @param[in] requestedAttributes Attributes which should be applied to bitmap.
+ * @return A bitmap which results from applying the requested attributes to the
+ *         bitmap passed-in, or the original bitmap passed in if the attributes
+ *         have no effect.
+ */
+Integration::BitmapPtr ApplyAttributesToBitmap( Integration::BitmapPtr bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
+
+/**
+ * @brief Apply downscaling to a bitmap according to requested attributes.
+ * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
+ **/
+Integration::BitmapPtr DownscaleBitmap( Integration::Bitmap& bitmap, ImageDimensions desired, FittingMode::Type fittingMode, SamplingMode::Type samplingMode );
+/**@}*/
+
+/**
+ * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
+ * @{
+ */
+
+/**
+ * @brief Destructive in-place downscaling by a power of 2 factor.
+ *
+ * A box filter with a 2x2 kernel is repeatedly applied as long as the result
+ * of the next downscaling step would not be smaller than the desired
+ * dimensions.
+ * @param[in,out] pixels The buffer both to read from and write the result to.
+ * @param[in]     pixelFormat The format of the image pointed at by pixels.
+ * @param[in]     inputWidth The width of the input image.
+ * @param[in]     inputHeight The height of the input image.
+ * @param[in]     desiredWidth The width the client is requesting.
+ * @param[in]     desiredHeight The height the client is requesting.
+ * @param[out]    outWidth  The resulting width after downscaling.
+ * @param[out]    outHeight The resulting height after downscaling.
+ */
+void DownscaleInPlacePow2( unsigned char * const pixels,
+                           Pixel::Format pixelFormat,
+                           unsigned int inputWidth,
+                           unsigned int inputHeight,
+                           unsigned int desiredWidth,
+                           unsigned int desiredHeight,
+                           FittingMode::Type fittingMode,
+                           SamplingMode::Type samplingMode,
+                           unsigned& outWidth,
+                           unsigned& outHeight );
+
+/**
+ * @brief Destructive in-place downscaling by a power of 2 factor.
+ *
+ * A box filter with a 2x2 kernel is repeatedly applied as long as the result
+ * of the next downscaling step would not be smaller than the desired
+ * dimensions.
+ * @param[in,out] pixels The buffer both to read from and write the result to.
+ * @param[in]     inputWidth The width of the input image.
+ * @param[in]     inputHeight The height of the input image.
+ * @param[in]     desiredWidth The width the client is requesting.
+ * @param[in]     desiredHeight The height the client is requesting.
+ * @param[out]    outWidth  The resulting width after downscaling.
+ * @param[out]    outHeight The resulting height after downscaling.
+ */
+void DownscaleInPlacePow2RGB888( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ */
+void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight,
+                                   BoxDimensionTest dimensionTest,
+                                   unsigned int& outWidth,
+                                   unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For the 2-byte packed 16 bit format RGB565.
+ */
+void DownscaleInPlacePow2RGB565( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
+ */
+void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
+                                        unsigned int inputWidth,
+                                        unsigned int inputHeight,
+                                        unsigned int desiredWidth,
+                                        unsigned int desiredHeight,
+                                        BoxDimensionTest dimensionTest,
+                                        unsigned int& outWidth,
+                                        unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For single-byte formats such as lum8 or alpha8.
+ */
+void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
+                                             unsigned int inputWidth,
+                                             unsigned int inputHeight,
+                                             unsigned int desiredWidth,
+                                             unsigned int desiredHeight,
+                                             BoxDimensionTest dimensionTest,
+                                             unsigned int& outWidth,
+                                             unsigned int& outHeight );
+
+/**
+ * @brief Rescales an input image into the exact output dimensions passed-in.
+ *
+ * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
+ * fastest results, at the expense of aliasing (noisy images) when downscaling.
+ * @note inPixels is allowed to alias outPixels if this is a downscaling,
+ * but not for upscaling.
+ */
+void PointSample( const unsigned char * inPixels,
+                  unsigned int inputWidth,
+                  unsigned int inputHeight,
+                  Pixel::Format pixelFormat,
+                  unsigned char * outPixels,
+                  unsigned int desiredWidth,
+                  unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
+ */
+void PointSample4BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 3-byte formats like RGB888 and BGR888.
+ */
+void PointSample3BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 2-byte formats like LA88.
+ */
+void PointSample2BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 1-byte formats like L8 and A8.
+ */
+void PointSample1BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @brief Resample input image to output image using a bilinear filter.
+ *
+ * Each output pixel is formed of a weighted sum of a 2x2 block of four input
+ * pixels
+ * @pre inPixels must not alias outPixels. The input image should be a totally
+ * separate buffer from the input one.
+ */
+void LinearSample( const unsigned char * __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   Pixel::Format pixelFormat,
+                   unsigned char * __restrict__ outPixels,
+                   ImageDimensions outDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for one byte per pixel formats.
+ */
+void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for two byte per pixel formats.
+ */
+void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for RGB565 16 bit pixel format.
+ */
+void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for three byte per pixel formats like RGB888.
+ */
+void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for four byte per pixel formats like RGBA888.
+ * @note, If used on RGBA8888, the A component will be blended independently.
+ */
+void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**@}*/
+
+/**
+ * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
+ * @{
+ */
+
+/**
+ * @brief Average adjacent pairs of pixels, overwriting the input array.
+ * @param[in,out] pixels The array of pixels to work on.
+ * @param[i]      width  The number of pixels in the array passed-in.
+ */
+void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
+
+/**
+ * @brief Average pixels at corresponding offsets in two scanlines.
+ *
+ * outputScanline is allowed to alias scanline1.
+ * @param[in] scanline1 First scanline of pixels to average.
+ * @param[in] scanline2 Second scanline of pixels to average.
+ * @param[out] outputScanline Destination for the averaged pixels.
+ * @param[in] width The widths of all the scanlines passed-in.
+ */
+void AverageScanlines1( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlines2( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlines3( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlinesRGBA8888( const unsigned char * scanline1,
+                               const unsigned char * scanline2,
+                               unsigned char * outputScanline,
+                               unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlinesRGB565( const unsigned char * scanline1,
+                             const unsigned char * scanline2,
+                             unsigned char* outputScanline,
+                             unsigned int width );
+/**@}*/
+
+/**
+ * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
+ * @{
+ */
+
+/**
+ * @brief Average two integer arguments.
+ * @return The average of two uint arguments.
+ * @param[in] a First component to average.
+ * @param[in] b Second component to average.
+ **/
+inline unsigned int AverageComponent( unsigned int a, unsigned int b )
+{
+  unsigned int avg = (a + b) >> 1u;
+  return avg;
+}
+
+/**
+ * @brief Average a pair of RGBA8888 pixels.
+ * @return The average of two RGBA8888 pixels.
+ * @param[in] a First pixel to average.
+ * @param[in] b Second pixel to average
+ **/
+inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
+{
+  const unsigned int avg =
+    ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
+    (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
+    (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
+    (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
+  return avg;
+  ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+  ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
+}
+
+/**
+ * @brief Average a pair of RGB565 pixels.
+ * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
+ * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
+ * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
+ **/
+inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
+{
+  const unsigned int avg =
+    (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
+    (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
+    (AverageComponent( a & 0x1f,   b & 0x1f ) );
+  return avg;
+}
+
+/** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
+inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
+{
+  DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
+  const unsigned int weightedAFixed = a * (65535u - fractBlend);
+  const unsigned int weightedBFixed = b * fractBlend;
+  const unsigned blended = (weightedAFixed + weightedBFixed);
+  return blended;
+}
+
+/** @brief Blend two 16.16 inputs to give a 16.32 output. */
+inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
+{
+  DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
+  // Blend while promoting intermediates to 16.32 fixed point:
+  const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
+  const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
+  const uint64_t blended = (weightedAFixed + weightedBFixed);
+  return blended;
+}
+
+/**
+ * @brief Blend 4 taps into one value using horizontal and vertical weights.
+ */
+inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
+  DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
+
+  const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
+  const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
+  const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
+  const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
+  return rounded;
+}
+
+/**@}*/
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H_ */
diff --git a/platform-abstractions/tizen/data-cache/data-compression.cpp b/platform-abstractions/tizen/data-cache/data-compression.cpp
new file mode 100644 (file)
index 0000000..d1076e1
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <memory.h>
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace DataCompression
+{
+
+std::size_t GetMaximumRleCompressedSize(const std::size_t inputLength)
+{
+  // RLE has worst case scenerio of double the input data
+  // e.g. if data is 1,2,3,4  = 4 bytes
+  // it will be encoded as 1,1, 1,2 1,3 1,4 = 8 bytes
+
+  // we also encode the original size into the stream to check
+  // the decode buffers are big enough and for corruption
+  return (inputLength * 2) + 4;  // 4 bytes is space for size
+
+}
+
+// Run length encode a byte stream, consisting of byte values.
+// Format is one byte for run-length, one byte value.
+// e.g. 10, 15, 20, 20, 20, 5, 5
+// is represented as :
+// 1,10
+// 1,15
+// 3,20
+// 2, 5
+// First 4 bytes are the size of the decoded data
+//
+void EncodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+                std::size_t& encodedSize)
+{
+  DALI_ASSERT_DEBUG( outputLength >= GetMaximumRleCompressedSize( inputLength ));
+
+  unsigned int index(0);
+  unsigned int runLength(0);
+  encodedSize = 0;
+
+  // encode the input length in the first 4 bytes.
+  output[ encodedSize++ ] =  inputLength & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 8) & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 16) & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 24) & 0xFF;
+
+  while( index < inputLength  )
+  {
+    unsigned char curChar = input[ index ];
+    runLength = 1;
+
+    if( ( (index + 1) == inputLength )         // is more data available
+        || input[index + 1] != curChar  )      // character doesn't match
+    {
+      // we out of data, or the next character doesn't match (run of zero)
+      index++;
+    }
+    else
+    {
+      while( ( (index+1) < inputLength ) &&
+               ( input[index + 1] == curChar ) &&
+               ( runLength < 0xFF ) )
+      {
+        runLength++;
+        index++;
+      }
+      index++;
+    }
+    output[ encodedSize++ ] = runLength;
+    output[ encodedSize++ ] = curChar;
+
+  }
+}
+
+bool DecodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+                std::size_t& decodedSize)
+{
+  unsigned int index(0);
+  unsigned int outputIndex(0);
+
+  // there should be at least 4 bytes for the size field
+  if( inputLength < 4)
+  {
+    DALI_LOG_ERROR("input buffer too small\n");
+    return false;
+  }
+
+  decodedSize = input[ index++ ] ;
+  decodedSize|= input[ index++ ]<<8 ;
+  decodedSize|= input[ index++ ]<<16 ;
+  decodedSize|= input[ index++ ]<<24 ;
+
+  // check the decoded data will fit in to
+  if( outputLength < decodedSize )
+  {
+    DALI_LOG_ERROR("buffer too small, buffer size =%d, data size = %d \n",outputLength, decodedSize);
+    return false;
+  }
+
+  while( (index+1)< inputLength )
+  {
+    // read the value and the run length
+    unsigned char runLength =  input[ index++ ];
+    unsigned char value = input[ index++ ];
+
+    if( (runLength + outputIndex) > decodedSize)
+    {
+      DALI_LOG_ERROR( "corrupted RLE data" );
+      // corrupted
+      return false;
+    }
+    // set the value run Length times
+    memset( &output[ outputIndex ], value, runLength * sizeof( unsigned char) );
+    outputIndex+= runLength;
+  }
+  if( outputIndex != decodedSize)
+  {
+    DALI_LOG_ERROR(" RLE data size missmatch");
+    return false;
+  }
+
+  return true;
+}
+
+} // DataCompression
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/data-cache/data-compression.h b/platform-abstractions/tizen/data-cache/data-compression.h
new file mode 100644 (file)
index 0000000..451b250
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef __DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H__
+#define __DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace DataCompression
+{
+
+/**
+ * Return the maximum size of a buffer required to hold a number of bytes.
+ * Required because compressing data, can end up being bigger
+ * than the original data.
+ * @return maximum buffer size required to compress inputSize
+ */
+std::size_t GetMaximumRleCompressedSize(const std::size_t inputSize);
+
+/**
+ * RLE Encodes an array of data
+ * @param input input data
+ * @param inputLength input data length in bytes
+ * @param output output data, pre-allocated by caller
+ * @param outputLength size of the output buffer in bytes
+ * @param encodedSize number of bytes written to outputBuffer
+ */
+void EncodeRle(  const unsigned char* input,
+                 const std::size_t inputLength,
+                 unsigned char* output,
+                 const std::size_t outputLength,
+                 std::size_t &encodedSize );
+
+/**
+ * RLE Decodes an array of data.
+ * @param[in] input input data
+ * @param[in] inputLength input data length in bytes
+ * @param[out] output output data, pre-allocated by caller, allocated using GetMaximumRleCompressedSize()
+ * @param[in] outputLength size of output data in bytes
+ * @param[out] decodedSize the number of bytes decoded into outputBuffer
+ */
+bool DecodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+               std::size_t& decodedSize);
+
+
+} // namespace DataCompression
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H__
diff --git a/platform-abstractions/tizen/file.list b/platform-abstractions/tizen/file.list
new file mode 100755 (executable)
index 0000000..b9efdd8
--- /dev/null
@@ -0,0 +1,31 @@
+# Add local source files here:
+
+tizen_platform_abstraction_src_files = \
+  $(tizen_platform_abstraction_src_dir)/tizen-platform-abstraction.cpp \
+  $(tizen_platform_abstraction_src_dir)/tizen-logging.cpp \
+  \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/resource-loader.cpp \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/resource-requester-base.cpp \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/resource-bitmap-requester.cpp \
+  \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/resource-thread-base.cpp \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/resource-thread-image.cpp \
+  \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/network/file-download.cpp \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/network/http-utils.cpp \
+  \
+  $(tizen_platform_abstraction_src_dir)/resource-loader/debug/resource-loader-debug.cpp \
+  \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-bmp.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-gif.cpp \
+    $(tizen_platform_abstraction_src_dir)/image-loaders/loader-ico.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-jpeg-turbo.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-ktx.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-png.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/loader-wbmp.cpp \
+  $(tizen_platform_abstraction_src_dir)/image-loaders/image-loader.cpp \
+  $(portable_platform_abstraction_src_dir)/image-operations.cpp
+
+# Add public headers here:
+
+# platform_abstraction_header_files =
diff --git a/platform-abstractions/tizen/image-loaders/image-loader-input.h b/platform-abstractions/tizen/image-loaders/image-loader-input.h
new file mode 100644 (file)
index 0000000..7aecffe
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef __DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H__
+#define __DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <dali/public-api/images/image-operations.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace ImageLoader
+{
+
+
+/**
+ * @brief A simple immutable struct to bundle together parameters for scaling an image.
+ * @ToDo Move this to adaptor internal?
+ * @ToDo Rename it after the move to ImageScalingParameters.
+ */
+class ScalingParameters
+{
+public:
+  ScalingParameters( ImageDimensions dimensions = ImageDimensions(), FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT ) :
+    dimensions(dimensions), scalingMode(fittingMode), samplingMode(samplingMode) {}
+  const ImageDimensions dimensions;
+  const FittingMode::Type scalingMode;
+  const SamplingMode::Type samplingMode;
+};
+
+  /**
+   * @brief Bundle-up the data pushed into an image loader.
+   */
+struct Input
+{
+  Input( FILE* file, ScalingParameters scalingParameters = ScalingParameters(), bool reorientationRequested = true ) :
+    file(file), scalingParameters(scalingParameters), reorientationRequested(reorientationRequested) {}
+  FILE* file;
+  ScalingParameters scalingParameters;
+  bool reorientationRequested;
+};
+
+} // ImageLoader
+} // TizenPlatform
+} // Dali
+
+#endif // __DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H__
diff --git a/platform-abstractions/tizen/image-loaders/image-loader.cpp b/platform-abstractions/tizen/image-loaders/image-loader.cpp
new file mode 100644 (file)
index 0000000..a87f31f
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "image-loader.h"
+
+#include <dali/devel-api/common/ref-counted-dali-vector.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/debug.h>
+
+#include "loader-bmp.h"
+#include "loader-gif.h"
+#include "loader-jpeg.h"
+#include "loader-png.h"
+#include "loader-ico.h"
+#include "loader-ktx.h"
+#include "loader-wbmp.h"
+#include "image-operations.h"
+#include "image-loader-input.h"
+#include "portable/file-closer.h"
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+namespace
+{
+typedef bool (*LoadBitmapFunction)( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+typedef bool (*LoadBitmapHeaderFunction)( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_IMAGE_LOADING" );
+#endif
+
+/**
+ * Stores the magic bytes, and the loader and header functions used for each image loader.
+ */
+struct BitmapLoader
+{
+  unsigned char magicByte1;        ///< The first byte in the file should be this
+  unsigned char magicByte2;        ///< The second byte in the file should be this
+  LoadBitmapFunction loader;       ///< The function which decodes the file
+  LoadBitmapHeaderFunction header; ///< The function which decodes the header of the file
+  Bitmap::Profile profile;         ///< The kind of bitmap to be created
+                                   ///  (addressable packed pixels or an opaque compressed blob).
+};
+
+/**
+ * Enum for file formats, has to be in sync with BITMAP_LOADER_LOOKUP_TABLE
+ */
+enum FileFormats
+{
+  // Unknown file format
+  FORMAT_UNKNOWN = -1,
+
+  // formats that use magic bytes
+  FORMAT_PNG = 0,
+  FORMAT_JPEG,
+  FORMAT_BMP,
+  FORMAT_GIF,
+  FORMAT_KTX,
+  FORMAT_ICO,
+  FORMAT_MAGIC_BYTE_COUNT,
+
+  // formats after this one do not use magic bytes
+  FORMAT_WBMP = FORMAT_MAGIC_BYTE_COUNT,
+  FORMAT_TOTAL_COUNT
+};
+
+/**
+ * A lookup table containing all the bitmap loaders with the appropriate information.
+ * Has to be in sync with enum FileFormats
+ */
+const BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_COUNT] =
+{
+  { Png::MAGIC_BYTE_1,  Png::MAGIC_BYTE_2,  LoadBitmapFromPng,  LoadPngHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  LoadBmpHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  LoadGifHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Ktx::MAGIC_BYTE_1,  Ktx::MAGIC_BYTE_2,  LoadBitmapFromKtx,  LoadKtxHeader,  Bitmap::BITMAP_COMPRESSED       },
+  { Ico::MAGIC_BYTE_1,  Ico::MAGIC_BYTE_2,  LoadBitmapFromIco,  LoadIcoHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { 0x0,                0x0,                LoadBitmapFromWbmp, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS },
+};
+
+const unsigned int MAGIC_LENGTH = 2;
+
+/**
+ * This code tries to predict the file format from the filename to help with format picking.
+ */
+struct FormatExtension
+{
+  const std::string extension;
+  FileFormats format;
+};
+
+const FormatExtension FORMAT_EXTENSIONS[] =
+{
+ { ".png",  FORMAT_PNG  },
+ { ".jpg",  FORMAT_JPEG },
+ { ".bmp",  FORMAT_BMP  },
+ { ".gif",  FORMAT_GIF  },
+ { ".ktx",  FORMAT_KTX  },
+ { ".ico",  FORMAT_ICO  },
+ { ".wbmp", FORMAT_WBMP }
+};
+
+const unsigned int FORMAT_EXTENSIONS_COUNT = sizeof(FORMAT_EXTENSIONS) / sizeof(FormatExtension);
+
+FileFormats GetFormatHint( const std::string& filename )
+{
+  FileFormats format = FORMAT_UNKNOWN;
+
+  for ( unsigned int i = 0; i < FORMAT_EXTENSIONS_COUNT; ++i )
+  {
+    unsigned int length = FORMAT_EXTENSIONS[i].extension.size();
+    if ( ( filename.size() > length ) &&
+         ( 0 == filename.compare( filename.size() - length, length, FORMAT_EXTENSIONS[i].extension ) ) )
+    {
+      format = FORMAT_EXTENSIONS[i].format;
+      break;
+    }
+  }
+
+  return format;
+}
+
+/**
+ * Checks the magic bytes of the file first to determine which Image decoder to use to decode the
+ * bitmap.
+ * @param[in]   fp      The file to decode
+ * @param[in]   format  Hint about what format to try first
+ * @param[out]  loader  Set with the function to use to decode the image
+ * @param[out]  header  Set with the function to use to decode the header
+ * @param[out]  profile The kind of bitmap to hold the bits loaded for the bitmap.
+ * @return true, if we can decode the image, false otherwise
+ */
+bool GetBitmapLoaderFunctions( FILE *fp,
+                               FileFormats format,
+                               LoadBitmapFunction& loader,
+                               LoadBitmapHeaderFunction& header,
+                               Bitmap::Profile& profile )
+{
+  unsigned char magic[MAGIC_LENGTH];
+  size_t read = fread(magic, sizeof(unsigned char), MAGIC_LENGTH, fp);
+
+  // Reset to the start of the file.
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  if (read != MAGIC_LENGTH)
+  {
+    return false;
+  }
+
+  bool loaderFound = false;
+  const BitmapLoader *lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
+  ImageLoader::Input defaultInput( fp );
+
+  // try hinted format first
+  if ( format != FORMAT_UNKNOWN )
+  {
+    lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + format;
+    if ( format >= FORMAT_MAGIC_BYTE_COUNT ||
+         ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] ) )
+    {
+      unsigned int width = 0;
+      unsigned int height = 0;
+      loaderFound = lookupPtr->header( fp, width, height );
+    }
+  }
+
+  // then try to get a match with formats that have magic bytes
+  if ( false == loaderFound )
+  {
+    for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
+          lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
+          ++lookupPtr )
+    {
+      if ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] )
+      {
+        // to seperate ico file format and wbmp file format
+        unsigned int width = 0;
+        unsigned int height = 0;
+        loaderFound = lookupPtr->header(fp, width, height);
+      }
+      if (loaderFound)
+      {
+        break;
+      }
+    }
+  }
+
+  // finally try formats that do not use magic bytes
+  if ( false == loaderFound )
+  {
+    for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
+          lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_TOTAL_COUNT;
+          ++lookupPtr )
+    {
+      // to seperate ico file format and wbmp file format
+      unsigned int width = 0;
+      unsigned int height = 0;
+      loaderFound = lookupPtr->header(fp, width, height);
+      if (loaderFound)
+      {
+        break;
+      }
+    }
+  }
+
+  // if a loader was found set the outputs
+  if ( loaderFound )
+  {
+    loader  = lookupPtr->loader;
+    header  = lookupPtr->header;
+    profile = lookupPtr->profile;
+  }
+
+  // Reset to the start of the file.
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  return loaderFound;
+}
+
+} // anonymous namespace
+
+
+namespace ImageLoader
+{
+
+bool ConvertStreamToBitmap( const ResourceType& resourceType, std::string path, FILE * const fp, const ResourceLoadingClient& client, BitmapPtr& ptr )
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+  DALI_ASSERT_DEBUG( ResourceBitmap == resourceType.id );
+
+  bool result = false;
+  BitmapPtr bitmap = 0;
+
+  if (fp != NULL)
+  {
+    LoadBitmapFunction function;
+    LoadBitmapHeaderFunction header;
+    Bitmap::Profile profile;
+
+    if ( GetBitmapLoaderFunctions( fp,
+                                   GetFormatHint( path ),
+                                   function,
+                                   header,
+                                   profile ) )
+    {
+      bitmap = Bitmap::New( profile, ResourcePolicy::OWNED_DISCARD );
+
+      DALI_LOG_SET_OBJECT_STRING( bitmap, path );
+      const BitmapResourceType& resType = static_cast<const BitmapResourceType&>( resourceType );
+      const ScalingParameters scalingParameters( resType.size, resType.scalingMode, resType.samplingMode );
+      const ImageLoader::Input input( fp, scalingParameters, resType.orientationCorrection );
+
+      // Check for cancellation now we have hit the filesystem, done some allocation, and burned some cycles:
+      // This won't do anything from synchronous API, it's only useful when called from another thread.
+      client.InterruptionPoint(); // Note: By design, this can throw an exception
+
+      // Run the image type decoder:
+      result = function( client, input, *bitmap );
+
+      if (!result)
+      {
+        DALI_LOG_WARNING( "Unable to convert %s\n", path.c_str() );
+        bitmap = 0;
+      }
+
+      // Apply the requested image attributes if not interrupted:
+      client.InterruptionPoint(); // Note: By design, this can throw an exception
+      bitmap = Internal::Platform::ApplyAttributesToBitmap( bitmap, resType.size, resType.scalingMode, resType.samplingMode );
+    }
+    else
+    {
+      DALI_LOG_WARNING( "Image Decoder for %s unavailable\n", path.c_str() );
+    }
+  }
+
+  ptr.Reset( bitmap.Get() );
+  return result;
+}
+
+ResourcePointer LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath )
+{
+  ResourcePointer resource;
+  BitmapPtr bitmap = 0;
+
+  Internal::Platform::FileCloser fc( resourcePath.c_str(), "rb");
+  FILE * const fp = fc.GetFile();
+  if( fp != NULL )
+  {
+    bool result = ConvertStreamToBitmap( resourceType, resourcePath, fp, StubbedResourceLoadingClient(), bitmap );
+    if( result && bitmap )
+    {
+      resource.Reset(bitmap.Get());
+    }
+  }
+  return resource;
+}
+
+///@ToDo: Rename GetClosestImageSize() functions. Make them use the orientation correction and scaling information. Requires jpeg loader to tell us about reorientation. [Is there still a requirement for this functionality at all?]
+ImageDimensions  GetClosestImageSize( const std::string& filename,
+                                      ImageDimensions size,
+                                      FittingMode::Type fittingMode,
+                                      SamplingMode::Type samplingMode,
+                                      bool orientationCorrection )
+{
+  unsigned int width = 0;
+  unsigned int height = 0;
+
+  Internal::Platform::FileCloser fc(filename.c_str(), "rb");
+  FILE *fp = fc.GetFile();
+  if (fp != NULL)
+  {
+    LoadBitmapFunction loaderFunction;
+    LoadBitmapHeaderFunction headerFunction;
+    Bitmap::Profile profile;
+
+    if ( GetBitmapLoaderFunctions( fp,
+                                   GetFormatHint(filename),
+                                   loaderFunction,
+                                   headerFunction,
+                                   profile ) )
+    {
+      const ImageLoader::Input input( fp, ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
+
+      const bool read_res = headerFunction( input, width, height );
+      if(!read_res)
+      {
+        DALI_LOG_WARNING("Image Decoder failed to read header for %s\n", filename.c_str());
+      }
+    }
+    else
+    {
+      DALI_LOG_WARNING("Image Decoder for %s unavailable\n", filename.c_str());
+    }
+  }
+  return ImageDimensions( width, height );
+}
+
+
+
+ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                     ImageDimensions size,
+                                     FittingMode::Type fittingMode,
+                                     SamplingMode::Type samplingMode,
+                                     bool orientationCorrection )
+{
+  unsigned int width = 0;
+  unsigned int height = 0;
+
+  // Get the blob of binary data that we need to decode:
+  DALI_ASSERT_DEBUG( resourceBuffer );
+  Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( resourceBuffer.Get() );
+
+  if( encodedBlob != 0 )
+  {
+    const size_t blobSize     = encodedBlob->GetVector().Size();
+    uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
+    DALI_ASSERT_DEBUG( blobSize > 0U );
+    DALI_ASSERT_DEBUG( blobBytes != 0U );
+
+    if( blobBytes != 0 && blobSize > 0U )
+    {
+      // Open a file handle on the memory buffer:
+      Internal::Platform::FileCloser fc( blobBytes, blobSize, "rb" );
+      FILE *fp = fc.GetFile();
+      if ( fp != NULL )
+      {
+        LoadBitmapFunction loaderFunction;
+        LoadBitmapHeaderFunction headerFunction;
+        Bitmap::Profile profile;
+
+        if ( GetBitmapLoaderFunctions( fp,
+                                       FORMAT_UNKNOWN,
+                                       loaderFunction,
+                                       headerFunction,
+                                       profile ) )
+        {
+          const ImageLoader::Input input( fp, ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
+          const bool read_res = headerFunction( input, width, height );
+          if( !read_res )
+          {
+            DALI_LOG_WARNING( "Image Decoder failed to read header for resourceBuffer\n" );
+          }
+        }
+      }
+    }
+  }
+  return ImageDimensions( width, height );
+}
+
+} // ImageLoader
+} // TizenPlatform
+} // Dali
diff --git a/platform-abstractions/tizen/image-loaders/image-loader.h b/platform-abstractions/tizen/image-loaders/image-loader.h
new file mode 100644 (file)
index 0000000..15e3318
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef __DALI_TIZEN_PLATFORM_IMAGE_LOADER_H__
+#define __DALI_TIZEN_PLATFORM_IMAGE_LOADER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/images/image-operations.h>
+#include <dali/integration-api/resource-cache.h>
+#include <dali/integration-api/resource-types.h>
+#include <dali/integration-api/bitmap.h>
+
+// INTERNAL INCLUDES
+#include "resource-loading-client.h"
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace ImageLoader
+{
+/**
+ * Convert a file stream into a bitmap.
+ * @param[in] resourceType The type of resource to convert.
+ * @param[in] path The path to the resource.
+ * @param[in] fp File Pointer. Closed on exit.
+ * @param[in] client The component that is initiating the conversion.
+ * @param[out] bitmap Pointer to write bitmap to
+ * @return true on success, false on failure
+ */
+bool ConvertStreamToBitmap( const Integration::ResourceType& resourceType, std::string path, FILE * const fp, const ResourceLoadingClient& client, Integration::BitmapPtr& ptr);
+
+/**
+ * Convert a bitmap and write to a file stream.
+ * @param[in] path The path to the resource.
+ * @param[in] fp File Pointer. Closed on exit.
+ * @param[out] bitmap Pointer from which to read bitmap
+ * @return true on success, false on failure
+ */
+bool ConvertBitmapToStream( std::string path, FILE * const fp, Integration::BitmapPtr& ptr );
+
+
+Integration::ResourcePointer LoadResourceSynchronously( const Integration::ResourceType& resourceType, const std::string& resourcePath );
+
+ImageDimensions  GetClosestImageSize( const std::string& filename,
+                          ImageDimensions size,
+                          FittingMode::Type fittingMode,
+                          SamplingMode::Type samplingMode,
+                          bool orientationCorrection );
+
+ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                          ImageDimensions size,
+                          FittingMode::Type fittingMode,
+                          SamplingMode::Type samplingMode,
+                          bool orientationCorrection );
+
+} // ImageLoader
+} // TizenPlatform
+} // Dali
+
+#endif // __DALI_TIZEN_PLATFORM_IMAGE_LOADER_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-bmp.cpp b/platform-abstractions/tizen/image-loaders/loader-bmp.cpp
new file mode 100644 (file)
index 0000000..9371b11
--- /dev/null
@@ -0,0 +1,1363 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "loader-bmp.h"
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+
+#include <cstdlib>
+
+namespace Dali
+{
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
+const unsigned int MaskForBFRGB565 = 0x80;
+const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
+
+enum BmpFormat
+{
+  BMP_RGB1 = 14,    //BI_RGB & bpp =1
+  BMP_RGB4,         //BI_RGB & bpp = 4
+  BMP_RGB8,         //BI_RGB & bpp = 8
+  BMP_RGB555,       //BI_RGB & bpp = 16
+  BMP_BITFIELDS555, //BI_BITFIELDS & 16bit & R:G:B = 5:5:5
+  BMP_BITFIELDS32,  //BI_BITFIELDS & 32bit & R:G:B:A = 8:8:8:8
+  BMP_RLE8,         //BI_RLE8
+  BMP_RLE4,         //BI_RLE4
+  BMP_BITFIELDS32V4,//BI_BITFIELDS & 32bit
+  BMP_RGB24V5,      //BI_RGB & bpp = 24 & bmp version5
+  BMP_NOTEXIST
+};
+
+struct BmpFileHeader
+{
+  unsigned short signature; // Bitmap file signature
+  unsigned int   fileSize;  // Bitmap file size in bytes
+  unsigned short reserved1; // Reserved bits
+  unsigned short reserved2; // Reserved bits
+  unsigned int   offset;    // Offset from BMP file header to BMP bits
+} __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
+
+struct BmpInfoHeader
+{
+  unsigned int   infoHeaderSize;  // Specifies the number of bytes required by the info header
+  unsigned int   width;           // The Image Width
+  int            height;          // The Image Height (negative value represents image data is flipped)
+  unsigned short planes;          // The number of color planes, must be 1
+  unsigned short bitsPerPixel;    // The bits per pixel
+  unsigned int   compression;     // The type of compression used by the image
+  unsigned int   imageSize;       // The size of the image in bytes
+  unsigned int   xPixelsPerMeter; // The number of pixels per meter in x axis
+  unsigned int   yPixelsPerMeter; // The number of pixels per meter in y axis
+  unsigned int   numberOfColors;  // The number of colors in the color table
+  unsigned int   importantColors; // The important color count
+} __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
+
+/**
+ * Template function to read from the file directly into our structure.
+ * @param[in]  fp     The file to read from
+ * @param[out] header The structure we want to store our information in
+ * @return true, if read successful, false otherwise
+ */
+template<typename T>
+inline bool ReadHeader(FILE* fp, T& header)
+{
+  unsigned int readLength = sizeof(T);
+
+  // Load the information directly into our structure
+  if (fread((void*)&header, 1, readLength, fp) != readLength)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+bool LoadBmpHeader(FILE *fp, unsigned int &width, unsigned int &height, BmpFileHeader &fileHeader, BmpInfoHeader &infoHeader)
+{
+  if (!ReadHeader(fp, fileHeader))
+  {
+    return false;
+  }
+
+  if (!ReadHeader(fp, infoHeader))
+  {
+    return false;
+  }
+
+  width = infoHeader.width;
+  height = infoHeader.height;
+
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 24 & bmp version5.
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @param[in]  padding padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB24V5(FILE *fp,
+                   PixelBuffer *pixels,
+                   unsigned int width,
+                   unsigned int height,
+                   unsigned int offset,
+                   bool topDown,
+                   unsigned int rowStride,
+                   unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
+    return false;
+  }
+  if ( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
+    return false;
+  }
+
+  for(unsigned int yPos = 0; yPos < height; yPos ++)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if(topDown)
+    {
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 3)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
+ * @param[in]  fp        The file to read from
+ * @param[out] pixels    The pointer that  we want to store bmp data  in
+ * @param[in]  width     bmp width
+ * @param[in]  height    bmp height
+ * @param[in]  offset    offset from bmp header to bmp image data
+ * @param[in]  topDown   indicate image data is read from bottom or from top
+ * @param[in]  rowStride bits span for each line
+ * @param[in]  padding   padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF32V4(FILE *fp,
+                  PixelBuffer *pixels,
+                  unsigned int width,
+                  unsigned int height,
+                  unsigned int offset,
+                  bool topDown,
+                  unsigned int rowStride,
+                  unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
+    return false;
+  }
+
+  for(unsigned int yPos = 0; yPos < height; yPos ++)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if(topDown)
+    {
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 4)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
+      }
+    }
+
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 32
+ * @param[in]  fp        The file to read from
+ * @param[out] pixels    The pointer that  we want to store bmp data  in
+ * @param[in]  width     bmp width
+ * @param[in]  height    bmp height
+ * @param[in]  offset    offset from bmp header to bmp image data
+ * @param[in]  topDown   indicate image data is read from bottom or from top
+ * @param[in]  rowStride bits span for each line
+ * @param[in]  padding   padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF32(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown,
+                unsigned int rowStride,
+                unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
+    return false;
+  }
+
+  for (unsigned int yPos = 0; yPos < height; yPos++)
+  {
+    PixelBuffer *pixelsPtr;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 4)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF565(FILE *fp,
+                 PixelBuffer *pixels,
+                 unsigned int width,
+                 unsigned int height,
+                 unsigned int offset,
+                 bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding RGB565 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking RGB565 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  unsigned int rowStride = width * 2;
+
+  for(unsigned int i = 0; i < height; i++)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( i * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - i) * rowStride);
+    }
+    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF555(FILE *fp,
+                 PixelBuffer *pixels,
+                 unsigned int width,
+                 unsigned int height,
+                 unsigned int offset,
+                 bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
+    return false;
+  }
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+
+  std::vector<char> raw(width * height * 2);
+  unsigned int rawStride = width * 2;
+  unsigned int rowStride = width * 3;
+
+  char *rawPtr = NULL;
+  for(unsigned int j = 0; j <  height; j ++)
+  {
+    rawPtr = &raw[0] + ( j * rawStride);
+    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    {
+      return false;
+    }
+  }
+
+  for (unsigned int yPos = 0; yPos < height; yPos++)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+
+    for(unsigned int k = 0; k < width; k ++)
+    {
+      int index = yPos * rawStride + 2 * k;
+      pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
+      pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
+      pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB555(FILE *fp,
+                  PixelBuffer *pixels,
+                  unsigned int width,
+                  unsigned int height,
+                  unsigned int offset,
+                  bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> raw(width * height * 2);
+  unsigned int rawStride = width * 2;
+  unsigned int rowStride = width * 3;
+
+  char *rawPtr = NULL;
+  for(unsigned int j = 0; j <  height; j ++)
+  {
+    rawPtr = &raw[0] + ( j * rawStride);
+    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    {
+      return false;
+    }
+  }
+  for(unsigned int i = 0; i < height; i++)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( i * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - i) * rowStride);
+    }
+    for(unsigned int k = 0; k < width; k ++)
+    {
+      int index = i * rawStride + 2 * k;
+      pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
+      pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
+      pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
+    }
+
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 1
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB1(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
+    return false;
+  }
+
+  unsigned char colorTable[8] = {0};
+  char cmd;
+  unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
+  std::vector<char> colorIndex(fillw * height);
+  unsigned int rowStride = fillw * 3; // RGB
+
+
+  if(fread(colorTable, 1, 8, fp) != 8)
+  {
+    return false;
+  }
+
+  for(unsigned int i = 0; i < fillw * height; i += 8)
+  {
+    if(fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i]     = (cmd >> 7) & 0x01;
+    colorIndex[i + 1] = (cmd >> 6) & 0x01;
+    colorIndex[i + 2] = (cmd >> 5) & 0x01;
+    colorIndex[i + 3] = (cmd >> 4) & 0x01;
+    colorIndex[i + 4] = (cmd >> 3) & 0x01;
+    colorIndex[i + 5] = (cmd >> 2) & 0x01;
+    colorIndex[i + 6] = (cmd >> 1) & 0x01;
+    colorIndex[i + 7] = (cmd & 0x01);
+  }
+
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < fillw; j ++)
+    {
+      int ctIndex = 0;
+      if((fillw * index + j ) < (fillw * height))
+      {
+        ctIndex = colorIndex[ fillw * index + j ];
+      }
+      else
+      {
+        break;
+      }
+      // temp solution for PLM bug P130411-5268, there is one mono bmp that cause DecodeRGB1 API crash.
+      if( ((3 * j + 2) < height * fillw * 3) && (ctIndex < 2))
+      {
+        pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+        pixelsPtr[3 * j + 1] = colorTable[4 * ctIndex + 1];
+        pixelsPtr[3 * j + 2] = colorTable[4 * ctIndex ];
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 4
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB4(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
+    return false;
+  }
+
+  char colorTable[64];
+  char cmd;
+  unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> colorIndex(fillw * height);
+  unsigned int rowStride = fillw  * 3;
+
+  if(fread(colorTable, 1, 64, fp) != 64)
+  {
+    return false;
+  }
+
+  for(unsigned int i = 0; i < fillw * height; i += 2)
+  {
+    if (fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i] = cmd >> 4;
+    colorIndex[i + 1] = cmd & (0x0F);
+  }
+  int ctIndex = 0;
+
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < fillw; j ++)
+    {
+      ctIndex = colorIndex[ fillw * index + j ];
+      pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+      pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
+      pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
+    }
+  }
+
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 8
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB8(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
+    return false;
+  }
+
+  std::vector<char> colorTable(1024);
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  char cmd;
+  std::vector<char> colorIndex(width * height);
+  unsigned int rowStride = width * 3;//RGB8->RGB24
+
+  if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+  {
+    return false;
+  }
+  for(unsigned int i = 0; i < width * height; i ++)
+  {
+    if (fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i] = cmd;
+  }
+  int ctIndex = 0;
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    PixelBuffer *pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < width; j ++)
+    {
+      ctIndex = colorIndex[ width * index + j ];
+      pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+      pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
+      pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RLE4 & bpp = 4
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRLE4(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
+    return false;
+  }
+  PixelBuffer *pixelsPtr = pixels;
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  char cmd[2];
+  unsigned int cmdStride = 2;
+  char colorTable[64];
+  std::vector<char> colorIndex(width * height >> 1);
+  std::vector<char> run;
+  int x = 0;
+  int y = 0;
+  int dx = 0;
+  int dy = 0;
+  width += (width & 1);
+  width = width >> 1;
+
+  bool finish = false;
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
+    return false;
+  }
+
+  if (fread(colorTable, 1, 64, fp) != 64)
+  {
+    return false;
+  }
+
+  while((x >> 1) + y * width < width * height)
+  {
+    if (finish)
+    {
+      break;
+    }
+    if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+    {
+      return false;
+    }
+    if(cmd[0] == 0) // ESCAPE
+    {
+      switch(cmd[1])
+      {
+        case 1: //end of bitmap
+          finish = true;
+          break;
+        case 0: // end of line
+          x = 0;
+          y ++;
+          break;
+        case 2: // delta
+          if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          dx = cmd[0] & (0xFF);
+          dy = cmd[1] & (0xFF);
+          x += dx;
+          y += dy;
+          break;
+        default:
+          // decode a literal run
+          unsigned int length = cmd[1] & (0xFF);
+          //size of run, which is word aligned
+          unsigned int bytesize = length;
+          bytesize += (bytesize & 1);
+          bytesize >>= 1;
+          bytesize += (bytesize & 1);
+          run.resize(bytesize);
+          if(fread(&run[0], 1, bytesize, fp) != bytesize)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          if((x & 1) == 0)
+          {
+            length += (length & 1);
+            length >>= 1;
+            for(unsigned int i = 0; i < length; i += 1)
+            {
+              colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
+            }
+          }
+          else
+          {
+            for(unsigned int i = 0; i < length; i ++)
+            {
+              if((i & 1) == 0)//copy high to low
+              {
+                colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
+              }
+              else //copy low to high
+              {
+                colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
+              }
+            }
+          }
+          x += cmd[1] & (0xFF);
+          break;
+      }
+    }
+    else
+    {
+      unsigned int length = cmd[0] & (0xFF);
+      if((x & 1) == 0)
+      {
+        length += (length & 1);
+        length >>= 1;
+        for(unsigned int i = 0; i < length; i ++)
+        {
+          colorIndex[(height-y-1)*width + i + (x >> 1)] = cmd[1];
+        }
+      }
+      else
+      {
+        for(unsigned int i = 0; i < length; i ++)
+        {
+          if((i & 1) == 0)
+          {
+            colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
+          }
+          else
+          {
+            colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
+          }
+        }
+      }
+      x += cmd[0] & (0xFF);
+    }
+  }
+
+  int ctIndexHigh = 0;
+  int ctIndexLow = 0;
+  for(unsigned int index = 0; index < (width * height ); index = index + 1)
+  {
+    ctIndexHigh = colorIndex[ index] >> 4;
+    ctIndexLow = colorIndex[index] & (0x0F);
+    pixelsPtr[6 * index ] = colorTable[4 * ctIndexHigh + 2];
+    pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
+    pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh ];
+    pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
+    pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
+    pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow ];
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RLE8 & bpp = 8
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRLE8(FILE *fp,
+                PixelBuffer *pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
+    return false;
+  }
+  PixelBuffer *pixelsPtr = pixels;
+  int x = 0;
+  int y = 0;
+  unsigned int cmdStride = 2;
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> colorTable(1024);
+  char cmd[2];
+  std::vector<char> colorIndex(width * height);
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
+    return false;
+  }
+
+  if (fread(&colorTable[0], 1, 1024, fp) != 1024)
+  {
+    return false;
+  }
+
+  int dx = 0;
+  int dy = 0;
+  bool finish = false;
+  unsigned int length = 0;
+  unsigned int copylength = 0;
+  std::vector<char> run;
+  while((x + y * width) < width * height )
+  {
+    if (finish)
+    {
+      break;
+    }
+    if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+    {
+      return false;
+    }
+
+    if(cmd[0] == 0)//ESCAPE
+    {
+      switch(cmd[1])
+      {
+        case 1: // end of bitmap
+          finish = true;
+          break;
+        case 0: // end of line
+          x = 0;
+          y ++;
+          break;
+        case 2: // delta
+          if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          dx = cmd[0] & (0xFF);
+          dy = cmd[1] & (0xFF);
+          x += dx;
+          y += dy;
+          break;
+        default:
+          //decode a literal run
+          length = cmd[1] & (0xFF);
+          copylength = length;
+          //absolute mode must be word-aligned
+          length += (length & 1);
+          run.resize(length);
+          if(fread(&run[0], 1, length, fp) != length)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+
+          for(unsigned int i = 0; i < length; i += 1)
+          {
+            colorIndex[x + width * (height - y - 1) + i] = run[i];
+          }
+          x += copylength;
+          break;
+      }
+    }// end if cmd[0] ==
+    else
+    {
+      length = cmd[0] & (0xFF);
+      for(unsigned int i = 0; i < length; i ++)
+      {
+        colorIndex[(height - y - 1) * width + x] = cmd[1];
+        x++;
+      }
+    }
+  }
+  int ctIndex = 0;
+  for(unsigned int index = 0; index < width * height; index = index + 1)
+  {
+    ctIndex = colorIndex[ index];
+    pixelsPtr[3 * index ] = colorTable[4 * ctIndex + 2];
+    pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
+    pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex ];
+  }
+  return true;
+}
+
+} // unnamed namespace
+
+bool LoadBmpHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  BmpFileHeader fileHeader;
+  BmpInfoHeader infoHeader;
+
+  bool ret = LoadBmpHeader( input.file, width, height, fileHeader, infoHeader );
+
+  return ret;
+}
+
+bool LoadBitmapFromBmp( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  BmpFormat customizedFormat = BMP_NOTEXIST;
+  BmpFileHeader fileHeader;
+  BmpInfoHeader infoHeader;
+
+  // Load the header info
+  unsigned int width, height;
+
+  if (!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
+  {
+      return false;
+  }
+
+  Pixel::Format pixelFormat = Pixel::RGB888;
+  switch(infoHeader.compression)
+  {
+    case 0:
+      switch (infoHeader.bitsPerPixel)
+      {
+        case 32:
+          pixelFormat = Pixel::BGR8888;
+          break;
+
+        case 24:
+          if(fileHeader.offset == FileHeaderOffsetOfRGB24V5)//0x8A
+          {
+            customizedFormat = BMP_RGB24V5;
+          }
+          else
+          {
+            pixelFormat = Pixel::RGB888;
+          }
+          break;
+
+        case 16:
+          customizedFormat = BMP_RGB555;
+          break;
+
+        case 8:
+          customizedFormat = BMP_RGB8;
+          break;
+
+        case 4: // RGB4
+          customizedFormat = BMP_RGB4;
+          break;
+
+        case 1: //RGB1
+          customizedFormat = BMP_RGB1;
+          break;
+        default:
+          DALI_LOG_WARNING("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
+          return false;
+      }
+    break;
+    case 1: //// RLE8
+    {
+      if(infoHeader.bitsPerPixel == 8)
+      {
+        customizedFormat = BMP_RLE8;
+      }
+      break;
+    }
+    case 2: // RLE4
+    {
+      if(infoHeader.bitsPerPixel == 4)
+      {
+        customizedFormat = BMP_RLE4;
+      }
+      break;
+    }
+    case 3: // // BI_BITFIELDS
+    {
+      if(infoHeader.bitsPerPixel == 16)
+      {
+        if( fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET) )
+        {
+          return false;
+        }
+
+        char mask;
+        if(fread(&mask, 1, 1, fp) != 1)
+        {
+          return false;
+        }
+
+        if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
+        {
+          pixelFormat = Pixel::RGB565;
+        }
+        else if((mask & 0x80) == 0)// mask is 0x 7C
+        {
+          customizedFormat = BMP_BITFIELDS555;
+        }
+        else
+        {
+          return false;
+        }
+      }
+      else if(infoHeader.bitsPerPixel == 32)
+      {
+        if(fileHeader.offset == FileHeaderOffsetOfBF32V4)// 0x7A
+        {
+          customizedFormat = BMP_BITFIELDS32V4;
+        }
+        else
+        {
+          customizedFormat = BMP_BITFIELDS32;
+        }
+      }
+      break;
+    }
+    default:
+      DALI_LOG_WARNING("Compression not supported for BMP files\n");
+      return false;
+  }
+
+  bool topDown = false;
+
+  // if height is negative, bitmap data is top down
+  if (infoHeader.height<0)
+  {
+    infoHeader.height =  abs(infoHeader.height);
+    height = infoHeader.height;
+    topDown = true;
+  }
+
+  unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >>3);
+
+  // bitmaps row stride is padded to 4 bytes
+  unsigned int padding = (rowStride % 4);
+  if (padding)
+  {
+    padding = 4 - padding;
+  }
+
+  PixelBuffer *pixels =  NULL;
+  int imageW = infoHeader.width;
+  int pixelBufferW = 0;
+  switch(customizedFormat)
+  {
+  case BMP_RLE8:
+  case BMP_RGB8:
+  case BMP_RGB4:
+  case BMP_RLE4:
+  case BMP_RGB555:
+  case BMP_BITFIELDS555:
+  {
+    pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
+    pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, pixelBufferW, abs(infoHeader.height));
+    break;
+  }
+  case BMP_RGB1:
+  {
+    pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
+    pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, pixelBufferW, abs(infoHeader.height));
+    break;
+  }
+  case BMP_BITFIELDS32:
+  case BMP_BITFIELDS32V4:
+  {
+    pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB8888, infoHeader.width, abs(infoHeader.height));
+    break;
+  }
+  case BMP_RGB24V5:
+  {
+    pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, infoHeader.width, infoHeader.height);
+    break;
+  }
+  default:
+    if(pixelFormat == Pixel::RGB565 )
+    {
+      pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
+      pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB565, pixelBufferW, abs(infoHeader.height));
+    }
+    else
+    {
+      pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, infoHeader.width, infoHeader.height);
+    }
+    break;
+  }
+
+  // TODO: Add scaling support
+
+  // Read the raw bitmap data
+  PixelBuffer *pixelsPtr;
+  bool decodeResult(false);
+  switch(customizedFormat)
+  {
+    case BMP_RGB1:
+    {
+      decodeResult = DecodeRGB1( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RGB4:
+    {
+      decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, infoHeader.height, 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RLE4:
+    {
+      decodeResult = DecodeRLE4( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_BITFIELDS32:
+    {
+      decodeResult = DecodeBF32(fp, pixels, infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    case BMP_BITFIELDS555:
+    {
+      decodeResult = DecodeBF555(fp, pixels,infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown);
+      break;
+    }
+    case BMP_RGB555:
+    {
+      decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
+      break;
+    }
+    case BMP_RGB8:
+    {
+      decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RLE8:
+    {
+      decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RGB24V5:
+    {
+      decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    case BMP_BITFIELDS32V4:
+    {
+      decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    default:
+    {
+      if(pixelFormat == Pixel::RGB565)
+      {
+        decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset,  topDown);
+      }
+      else
+      {
+        for (unsigned int yPos = 0; yPos < height; yPos++)
+        {
+          if (topDown)
+          {
+            // the data in the file is top down, and we store the data top down
+            pixelsPtr = pixels + ( yPos * rowStride);
+          }
+          else
+          {
+            // the data in the file is bottom up, and we store the data top down
+            pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+          }
+
+          if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            break;
+          }
+
+          // If 24 bit mode then swap Blue and Red pixels
+          // BGR888 doesn't seem to be supported by dali-core
+          if (infoHeader.bitsPerPixel == 24 )
+          {
+            for(unsigned int i = 0; i < rowStride; i += 3)
+            {
+              unsigned char temp = pixelsPtr[i];
+              pixelsPtr[i] = pixelsPtr[i+2];
+              pixelsPtr[i+2] = temp;
+            }
+          }
+
+          if (padding)
+          {
+            if( fseek(fp, padding, SEEK_CUR) )  // move past the padding.
+            {
+              DALI_LOG_ERROR("Error moving past BMP padding\n");
+            }
+          }
+        }
+        decodeResult = true;
+      }
+      break;
+    }
+  } // switch
+
+  if( !decodeResult )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/image-loaders/loader-bmp.h b/platform-abstractions/tizen/image-loaders/loader-bmp.h
new file mode 100644 (file)
index 0000000..41872aa
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_BMP_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_BMP_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Bmp
+{
+const unsigned char MAGIC_BYTE_1 = 0x42;
+const unsigned char MAGIC_BYTE_2 = 0x4D;
+} // namespace Bmp
+
+/**
+ * Loads the bitmap from an BMP file.  This function checks the header first
+ * and if it is not a BMP file, then it returns straight away.
+ * @param[in]  fp      Pointer to the Image file
+ * @param[in]  bitmap  The bitmap class where the decoded image will be stored
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromBmp( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+/**
+ * Loads the header of a BMP file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]   attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadBmpHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_LOADER_BMP_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-gif.cpp b/platform-abstractions/tizen/image-loaders/loader-gif.cpp
new file mode 100644 (file)
index 0000000..cac1bff
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "loader-gif.h"
+
+#include <gif_lib.h>
+#include <cstdlib>
+
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+
+namespace Dali
+{
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+// simple class to enforce clean-up of GIF structures
+struct AutoCleanupGif
+{
+  AutoCleanupGif(GifFileType*& _gifInfo)
+  : gifInfo(_gifInfo)
+  {
+  }
+
+  ~AutoCleanupGif()
+  {
+    if(NULL != gifInfo)
+    {
+      // clean up GIF resources
+      DGifCloseFile(gifInfo);
+    }
+  }
+
+  GifFileType*& gifInfo;
+};
+
+// Simple class to enforce clean-up of PixelBuffer
+struct AutoDeleteBuffer
+{
+  AutoDeleteBuffer( PixelBuffer* _buffer )
+  : buffer( _buffer )
+  {
+  }
+
+  ~AutoDeleteBuffer()
+  {
+    delete []buffer;
+  }
+
+  PixelBuffer* buffer;
+};
+
+// Used in the GIF interlace algorithm to determine the starting byte and the increment required
+// for each pass.
+struct InterlacePair
+{
+  unsigned int startingByte;
+  unsigned int incrementalByte;
+};
+
+// Used in the GIF interlace algorithm to determine the order and which location to read data from
+// the file.
+const InterlacePair INTERLACE_PAIR_TABLE [] = {
+  { 0, 8 }, // Starting at 0, read every 8 bytes.
+  { 4, 8 }, // Starting at 4, read every 8 bytes.
+  { 2, 4 }, // Starting at 2, read every 4 bytes.
+  { 1, 2 }, // Starting at 1, read every 2 bytes.
+};
+const unsigned int INTERLACE_PAIR_TABLE_SIZE( sizeof( INTERLACE_PAIR_TABLE ) / sizeof( InterlacePair ) );
+
+/// Function used by Gif_Lib to read from the image file.
+int ReadDataFromGif(GifFileType *gifInfo, GifByteType *data, int length)
+{
+  FILE *fp = reinterpret_cast<FILE*>(gifInfo->UserData);
+  return fread( data, sizeof( GifByteType ), length, fp);
+}
+
+/// Loads the GIF Header.
+bool LoadGifHeader(FILE *fp, unsigned int &width, unsigned int &height, GifFileType** gifInfo)
+{
+  *gifInfo = DGifOpen(reinterpret_cast<void*>(fp), ReadDataFromGif);
+
+  if ( !(*gifInfo) )
+  {
+    return false;
+  }
+
+  width  = (*gifInfo)->SWidth;
+  height = (*gifInfo)->SHeight;
+
+  // No proper size in GIF.
+  if ( width <= 0 || height <= 0 )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+/// Decode the GIF image.
+bool DecodeImage( GifFileType* gifInfo, PixelBuffer* decodedData, const unsigned int width, const unsigned int height, const unsigned int bytesPerRow )
+{
+  if ( gifInfo->Image.Interlace )
+  {
+    // If the image is interlaced, then use the GIF interlace algorithm to read the file appropriately.
+
+    const InterlacePair* interlacePairPtr( INTERLACE_PAIR_TABLE );
+    for ( unsigned int interlacePair = 0; interlacePair < INTERLACE_PAIR_TABLE_SIZE; ++interlacePair, ++interlacePairPtr )
+    {
+      for( unsigned int currentByte = interlacePairPtr->startingByte; currentByte < height; currentByte += interlacePairPtr->incrementalByte )
+      {
+        PixelBuffer* row = decodedData + currentByte * bytesPerRow;
+        if ( DGifGetLine( gifInfo, row, width ) == GIF_ERROR )
+        {
+          DALI_LOG_ERROR( "GIF Loader: Error reading Interlaced GIF\n" );
+          return false;
+        }
+      }
+    }
+  }
+  else
+  {
+    // Non-interlace does not require any erratic reading / jumping.
+    PixelBuffer* decodedDataPtr( decodedData );
+
+    for ( unsigned int row = 0; row < height; ++row )
+    {
+      if ( DGifGetLine( gifInfo, decodedDataPtr, width ) == GIF_ERROR)
+      {
+        DALI_LOG_ERROR( "GIF Loader: Error reading non-interlaced GIF\n" );
+        return false;
+      }
+      decodedDataPtr += bytesPerRow;
+    }
+  }
+  return true;
+}
+
+// Retrieves the colors used in the GIF image.
+GifColorType* GetImageColors( SavedImage* image, GifFileType* gifInfo )
+{
+  GifColorType* color( NULL );
+  if ( image->ImageDesc.ColorMap )
+  {
+    color = image->ImageDesc.ColorMap->Colors;
+  }
+  else
+  {
+    // if there is no color map for this image use the default one
+    color = gifInfo->SColorMap->Colors;
+  }
+  return color;
+}
+
+/// Called when we want to handle IMAGE_DESC_RECORD_TYPE
+bool HandleImageDescriptionRecordType( Bitmap& bitmap, GifFileType* gifInfo, unsigned int width, unsigned int height, bool& finished )
+{
+  if ( DGifGetImageDesc( gifInfo ) == GIF_ERROR )
+  {
+    DALI_LOG_ERROR( "GIF Loader: Error getting Image Description\n" );
+    return false;
+  }
+
+  // Ensure there is at least 1 image in the GIF.
+  if ( gifInfo->ImageCount < 1 )
+  {
+    DALI_LOG_ERROR( "GIF Loader: No Images\n" );
+    return false;
+  }
+
+  SavedImage* image( &gifInfo->SavedImages[ gifInfo->ImageCount - 1 ] );
+  const GifImageDesc& desc( image->ImageDesc );
+
+  // Create a buffer to store the decoded data.
+  PixelBuffer* decodedData( new PixelBuffer[ width * height * sizeof( GifPixelType ) ] );
+  AutoDeleteBuffer autoDeleteBuffer( decodedData );
+
+  const unsigned int bytesPerRow( width * sizeof( GifPixelType ) );
+  const unsigned int actualWidth( desc.Width );
+  const unsigned int actualHeight( desc.Height );
+
+  // Decode the GIF Image
+  if ( !DecodeImage( gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow ) )
+  {
+    return false;
+  }
+
+  // Get the colormap for the GIF
+  GifColorType* color( GetImageColors( image, gifInfo ) );
+
+  // If it's an animated GIF, we still only read the first image
+
+  // Create and populate pixel buffer.
+
+  Pixel::Format pixelFormat( Pixel::RGB888 );
+  PixelBuffer *pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, actualWidth, actualHeight );
+
+  for (unsigned int row = 0; row < actualHeight; ++row)
+  {
+    for (unsigned int column = 0; column < actualWidth; ++column)
+    {
+      unsigned char index = decodedData[row * width + column];
+
+      pixels[0] = color[index].Red;
+      pixels[1] = color[index].Green;
+      pixels[2] = color[index].Blue;
+      pixels += 3;
+    }
+  }
+
+  finished = true;
+
+  return true;
+}
+
+/// Called when we want to handle EXTENSION_RECORD_TYPE
+bool HandleExtensionRecordType( GifFileType* gifInfo )
+{
+  SavedImage image;
+  image.ExtensionBlocks     = NULL;
+  image.ExtensionBlockCount = 0;
+  GifByteType *extensionByte( NULL );
+
+  // Not really interested in the extensions so just skip them unless there is an error.
+  for ( int extRetCode = DGifGetExtension( gifInfo, &image.Function, &extensionByte );
+        extensionByte != NULL;
+        extRetCode = DGifGetExtensionNext( gifInfo, &extensionByte ) )
+  {
+    if ( extRetCode == GIF_ERROR )
+    {
+      DALI_LOG_ERROR( "GIF Loader: Error reading GIF Extension record.\n" );
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // unnamed namespace
+
+bool LoadGifHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  GifFileType* gifInfo = NULL;
+  AutoCleanupGif autoCleanupGif(gifInfo);
+  FILE* const fp = input.file;
+
+  return LoadGifHeader(fp, width, height, &gifInfo);
+}
+
+bool LoadBitmapFromGif( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  FILE* const fp = input.file;
+  // Load the GIF Header file.
+
+  GifFileType* gifInfo( NULL );
+  unsigned int width( 0 );
+  unsigned int height( 0 );
+  if ( !LoadGifHeader( fp, width, height, &gifInfo ) )
+  {
+    return false;
+  }
+  AutoCleanupGif autoGif( gifInfo );
+
+  // Check each record in the GIF file.
+
+  bool finished( false );
+  GifRecordType recordType( UNDEFINED_RECORD_TYPE );
+  for ( int returnCode = DGifGetRecordType( gifInfo, &recordType );
+        !finished && recordType != TERMINATE_RECORD_TYPE;
+        returnCode = DGifGetRecordType( gifInfo, &recordType ) )
+  {
+    if ( returnCode == GIF_ERROR )
+    {
+      DALI_LOG_ERROR( "GIF Loader: Error getting Record Type\n" );
+      return false;
+    }
+
+    if( IMAGE_DESC_RECORD_TYPE == recordType )
+    {
+      if ( !HandleImageDescriptionRecordType( bitmap, gifInfo, width, height, finished ) )
+      {
+        return false;
+      }
+    }
+    else if ( EXTENSION_RECORD_TYPE == recordType )
+    {
+      if ( !HandleExtensionRecordType( gifInfo ))
+      {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/image-loaders/loader-gif.h b/platform-abstractions/tizen/image-loaders/loader-gif.h
new file mode 100644 (file)
index 0000000..d2afd3b
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_GIF_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_GIF_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Gif
+{
+const unsigned char MAGIC_BYTE_1 = 0x47;
+const unsigned char MAGIC_BYTE_2 = 0x49;
+} // namespace Gif
+
+/**
+ * Loads the bitmap from a GIF file.  This function checks the header first
+ * and if it is not a GIF file, then it returns straight away.
+ * @note For animated GIFs, only the first image is displayed
+ * @param[in]  fp      Pointer to the Image file
+ * @param[in]  bitmap  The bitmap class where the decoded image will be stored
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromGif( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+/**
+ * Loads the header of a GIF file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[in/out]  width   Is set with the width of the image
+ * @param[in/out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadGifHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_LOADER_GIF_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-ico.cpp b/platform-abstractions/tizen/image-loaders/loader-ico.cpp
new file mode 100644 (file)
index 0000000..8bea0d1
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Derived from Enlightenment file evas_image_load_ico.c[1]  which is licensed
+ * under the BSD 2-clause license[2] reproduced below.
+ *
+ * [1][http://web.archive.org/web/20141201151111/http://git.enlightenment.org/core/efl.git/tree/src/modules/evas/loaders/ico/evas_image_load_ico.c]
+ * [2][http://web.archive.org/web/20140717012400/https://git.enlightenment.org/core/efl.git/about/]
+ *
+ * Copyright (C) 2002-2012 Carsten Haitzler, Dan Sinclair, Mike Blumenkrantz,
+ * Samsung Electronics 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.
+ */
+
+// HEADER
+#include "loader-ico.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+
+namespace Dali
+{
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+//reserved 2 bytes + type 2 bytes + count 2 bytes + count * 16 bytes
+const unsigned char ICO_FILE_HEADER = 22;
+// info header 40 bytes = size 4 bytes + width 4 bytes + height 4 bytes + planes 2 bytes + bitcount 2 bytes
+// + compression 4 bytes + imagesize 4 bytes + xpixelsPerM 4 bytes + ypixelsPerM 4 bytes + colorsUsed 4 bytes + colorImportant 4 bytes
+// besides, there are rgba color data = numberOfColors * 4 bytes
+const unsigned char ICO_IMAGE_INFO_HEADER = 40;
+
+typedef unsigned char  DATA8;
+#define A_VAL(p) (((DATA8 *)(p))[3])
+
+#define RGB_JOIN(r,g,b) \
+                (((r) << 16) + ((g) << 8) + (b))
+
+#define ARGB_JOIN(a,r,g,b) \
+                (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
+#define IMG_TOO_BIG(w, h) \
+       ((((unsigned long long)w) * ((unsigned long long)h)) >= \
+           ((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
+
+bool read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+  unsigned char b[2];
+
+  if (*position + 2 > length)
+  {
+    return false;
+  }
+  b[0] = map[(*position)++];
+  b[1] = map[(*position)++];
+  *ret = (b[1] << 8) | b[0];
+  return true;
+}
+
+bool read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+  unsigned char b[4];
+  unsigned int i;
+
+  if (*position + 4 > length)
+  {
+    return false;
+  }
+  for (i = 0; i < 4; i++)
+  {
+    b[i] = map[(*position)++];
+  }
+  *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+  return true;
+}
+
+bool read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+  if (*position + 1 > length)
+  {
+    return false;
+  }
+  *ret = map[(*position)++];
+  return true;
+}
+
+bool read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+  if (*position + size > length)
+  {
+    return false;
+  }
+  memcpy(buffer, map + *position, size);
+  *position += size;
+  return true;
+}
+
+enum
+{
+  SMALLEST,
+  BIGGEST,
+  SMALLER,
+  BIGGER
+};
+
+enum
+{
+  ICON = 1,
+  CURSOR = 2
+};
+
+struct IcoData
+{
+  int pdelta;
+  int w, h;
+  int cols;
+  int bpp, planes;
+  int hot_x, hot_y;
+  unsigned int bmoffset, bmsize;
+};
+
+bool LoadIcoHeaderHelper( FILE* fp,
+                          IcoData& chosen,
+                          Dali::Vector<unsigned char>& map,
+                          unsigned int& fsize )
+{
+  memset( &chosen, 0, sizeof(chosen) );
+
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  size_t position = 0;
+  unsigned short word;
+  unsigned char byte;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking ICO data\n");
+    return false;
+  }
+
+  long positionIndicator = ftell(fp);
+  fsize = 0u;
+
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking ICO data\n");
+    return false;
+  }
+
+  if (fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
+  {
+    return false;
+  }
+  map.Resize(fsize);
+
+  if(fread(&map[0], 1, fsize, fp) != fsize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!");
+    return false;
+  }
+
+  int search = BIGGEST;
+  unsigned short reserved, type, count;
+  if (!read_ushort(&map[0], fsize, &position, &reserved))
+  {
+    return false;
+  }
+  if (!read_ushort(&map[0], fsize, &position, &type))
+  {
+    return false;
+  }
+  if (!read_ushort(&map[0], fsize, &position, &count))
+  {
+    return false;
+  }
+  if (!((reserved == 0) &&
+       ((type == ICON) || (type == CURSOR)) && (count != 0)))
+  {
+    return false;
+  }
+  search = BIGGEST;
+  chosen.pdelta = 0;
+  bool have_choice = false;
+
+  for (unsigned short i = 0; i < count; i++)
+  {
+    unsigned char tw = 0, th = 0, tcols = 0;
+    if (!read_uchar(&map[0], fsize, &position, &tw))
+    {
+      return false;
+    }
+    int w = tw;
+    if (w <= 0)
+    {
+      w = 256;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &th))
+    {
+      return false;
+
+    }
+    int h = th;
+    if (h <= 0)
+    {
+      h = 256;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &tcols))
+    {
+      return false;
+    }
+    int cols = tcols;
+    if (cols <= 0)
+    {
+      cols = 256;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &byte))
+    {
+      return false;
+    }
+    if (!read_ushort(&map[0], fsize, &position, &word))
+    {
+      return false;
+    }
+    int planes=0;
+    if (type == 1)
+    {
+      planes = word;
+    }
+    //else hot_x = word;
+    if (!read_ushort(&map[0], fsize, &position, &word))
+    {
+      return false;
+    }
+    int bpp=0;
+    if (type == 1)
+    {
+      bpp = word;
+    }
+    //else hot_y = word;
+    unsigned int bmoffset, bmsize;
+    if (!read_uint(&map[0], fsize, &position, &bmsize))
+    {
+      return false;
+    }
+    if (!read_uint(&map[0], fsize, &position, &bmoffset))
+    {
+      return false;
+    }
+    if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
+    {
+      return false;
+    }
+    if (search == BIGGEST)
+    {
+      int pdelta = w * h;
+      if ((!have_choice) ||
+       ((pdelta >= chosen.pdelta) &&
+           (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+               ((bpp < 3) && (cols >= chosen.cols)))))
+      {
+        have_choice = true;
+        chosen.pdelta = pdelta;
+        chosen.w = w;
+        chosen.h = h;
+        chosen.cols = cols;
+        chosen.bpp = bpp;
+        chosen.planes = planes;
+        chosen.bmsize = bmsize;
+        chosen.bmoffset = bmoffset;
+      }
+    }
+  }
+
+  if (chosen.bmoffset == 0)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+}//unnamed namespace
+
+bool LoadIcoHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  IcoData chosen;
+  Dali::Vector<unsigned char> map;
+  unsigned int fsize;
+  FILE* const fp = input.file;
+
+  if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
+  {
+    return false;
+  }
+
+  width = chosen.w;
+  height = chosen.h;
+
+  return true;
+}
+
+bool LoadBitmapFromIco( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  IcoData chosen;
+  Dali::Vector<unsigned char> map;
+  unsigned int fsize;
+  FILE* const fp = input.file;
+
+  if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
+  {
+    return false;
+  }
+
+  Dali::Vector<unsigned int> pal;
+  Dali::Vector<unsigned int> surface;
+  Dali::Vector<unsigned char> maskbuf;
+  Dali::Vector<unsigned char> pixbuf;
+  pal.Resize(256 * 4);
+
+  unsigned int dword;
+  unsigned short word;
+
+  int diff_size = 0;
+  unsigned int* pix;
+  PixelBuffer* pixels = NULL;
+
+  size_t position = chosen.bmoffset;//22 == position
+
+  int w = chosen.w;
+  int h = chosen.h;
+  int cols = chosen.cols;
+
+  // read bmp header time... let's do some checking
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // headersize - dont care
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // width
+  }
+  if (dword > 0)
+  {
+    if ((int)dword != w)
+    {
+      w = dword;
+      diff_size = 1;
+    }
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // height
+  }
+  if (dword > 0)
+  {
+    if ((int)dword != (h * 2))
+    {
+      h = dword / 2;
+      diff_size = 1;
+    }
+  }
+  if (diff_size)
+  {
+    DALI_LOG_WARNING("Broken ICO file!");
+  }
+  if (!read_ushort(&map[0], fsize, &position, &word))
+  {
+    return false; // planes
+  }
+  //planes2 = word;
+  if (!read_ushort(&map[0], fsize, &position, &word))
+  {
+    return false; // bitcount
+  }
+  unsigned int bitcount = word;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // compression
+  }
+  //compression = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // imagesize
+  }
+  //imagesize = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // z pixels per m
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // y pizels per m
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // colors used
+  }
+  //colorsused = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // colors important
+  }
+  //colorsimportant = dword;
+  surface.Resize(w * h * 4);
+
+  memset(&surface[0], 0, w * h * 4);
+
+  for(int i = 0; i < cols ; i ++)
+  {
+    unsigned char a, r, g, b;
+
+    if (!read_uchar(&map[0], fsize, &position, &b))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &g))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &r))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &a))
+    {
+      return false;
+    }
+    a = 0xff;
+    pal[i] = ARGB_JOIN(a, r, g, b);
+  }
+
+  if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
+       (bitcount == 24) || (bitcount == 32)))
+  {
+    return false;
+  }
+  int stride = ((w + 31) / 32);
+
+  maskbuf.Resize(stride * h);
+  pixbuf.Resize(stride * 32 * 4); // more than enough
+
+  unsigned int none_zero_alpha = 0;
+  if (bitcount == 1)
+  {
+    int pstride = stride * 4;
+    for (int i = 0; i < h; i++)
+    {
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
+      {
+        return false;
+      }
+      unsigned char* p = &pixbuf[0];
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        if (j >= (int)w)
+        {
+          break;
+        }
+        if ((j & 0x7) == 0x0)
+        {
+          *pix = pal[*p >> 7];
+        }
+        else if ((j & 0x7) == 0x1)
+        {
+          *pix = pal[(*p >> 6) & 0x1];
+        }
+        else if ((j & 0x7) == 0x2)
+        {
+          *pix = pal[(*p >> 5) & 0x1];
+        }
+        else if ((j & 0x7) == 0x3)
+        {
+          *pix = pal[(*p >> 4) & 0x1];
+        }
+        else if ((j & 0x7) == 0x4)
+        {
+          *pix = pal[(*p >> 3) & 0x1];
+        }
+        else if ((j & 0x7) == 0x5)
+        {
+          *pix = pal[(*p >> 2) & 0x1];
+        }
+        else if ((j & 0x7) == 0x6)
+        {
+          *pix = pal[(*p >> 1) & 0x1];
+        }
+        else
+        {
+          *pix = pal[*p & 0x1];
+          p++;
+        }
+        pix++;
+      }
+    }
+  }
+  else if (bitcount == 4)
+  {
+    int pstride = ((w + 7) / 8) * 4;
+    for (int i = 0; i < h; i++)
+    {
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
+      {
+        return false;
+      }
+      unsigned char* p = &pixbuf[0];
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        if (j >= (int)w)
+        {
+          break;
+        }
+        if ((j & 0x1) == 0x1)
+        {
+          *pix = pal[*p & 0x0f];
+          p++;
+        }
+        else
+        {
+          *pix = pal[*p >> 4];
+        }
+        pix++;
+      }
+    }
+  }
+  else if (bitcount == 8)
+  {
+    int pstride = ((w + 3) / 4) * 4;
+    for (int i = 0; i < h; i++)
+    {
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
+      {
+        return false;
+      }
+      unsigned char* p = &pixbuf[0];
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        if (j >= (int)w)
+        {
+          break;
+        }
+        *pix = pal[*p];
+        p++;
+        pix++;
+      }
+    }
+  }
+  else if (bitcount == 24)
+  {
+    int pstride = w * 3;
+    for (int i = 0; i < h; i++)
+    {
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
+      {
+        return false;
+      }
+      unsigned char* p = &pixbuf[0];
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        unsigned char a, r, g, b;
+
+        if (j >= (int)w)
+        {
+          break;
+        }
+        b = p[0];
+        g = p[1];
+        r = p[2];
+        p += 3;
+        a = 0xff;
+        *pix = ARGB_JOIN(a, r, g, b);
+        pix++;
+      }
+    }
+  }
+  else if (bitcount == 32)
+  {
+    int pstride = w * 4;
+    for (int i = 0; i < h; i++)
+    {
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
+      {
+        return false;
+      }
+      unsigned char* p = &pixbuf[0];
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        unsigned char a, r, g, b;
+        if (j >= (int)w)
+        {
+          break;
+        }
+        b = p[0];
+        g = p[1];
+        r = p[2];
+        a = p[3];
+        p += 4;
+        if (a)
+        {
+          none_zero_alpha = 1;
+        }
+        *pix = ARGB_JOIN(a, r, g, b);
+        pix++;
+      }
+    }
+  }
+  if (!none_zero_alpha)
+  {
+    if (!read_mem(&map[0], fsize, &position, &maskbuf[0], stride * 4 * h))
+    {
+      return false;
+    }
+    // apply mask
+    for (int i = 0; i < h; i++)
+    {
+      unsigned char *m;
+
+      pix = &surface[0] + ((h - 1 - i) * w);
+
+      m = &maskbuf[0] + (stride * i * 4);
+      if (i >= (int)h)
+      {
+        continue;
+      }
+      for (int j = 0; j < w; j++)
+      {
+        if (j >= (int)w)
+        {
+          break;
+        }
+        if (*m & (1 << (7 - (j & 0x7))))
+        {
+          A_VAL(pix) = 0x00;
+        }
+        else
+        {
+          A_VAL(pix) = 0xff;
+        }
+        if ((j & 0x7) == 0x7)
+        {
+          m++;
+        }
+        pix++;
+      }
+    }
+  }
+  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGBA8888, w, h);
+  memset(pixels, 0, w * h * 4);
+  memcpy(pixels, (unsigned char*)&surface[0], w * h * 4);
+
+  return true;
+}
+
+}
+
+}
diff --git a/platform-abstractions/tizen/image-loaders/loader-ico.h b/platform-abstractions/tizen/image-loaders/loader-ico.h
new file mode 100644 (file)
index 0000000..7b56737
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_ICO_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_ICO_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Ico
+{
+//00 00 01 00 01 00 20 20
+const unsigned char MAGIC_BYTE_1 = 0x00;
+const unsigned char MAGIC_BYTE_2 = 0x00;
+}
+
+bool LoadBitmapFromIco( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+bool LoadIcoHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+}
+
+}
+#endif
diff --git a/platform-abstractions/tizen/image-loaders/loader-jpeg-turbo.cpp b/platform-abstractions/tizen/image-loaders/loader-jpeg-turbo.cpp
new file mode 100755 (executable)
index 0000000..1e41437
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL HEADERS
+#include "loader-jpeg.h"
+#include "resource-loading-client.h"
+#include <dali/integration-api/bitmap.h>
+#include <resource-loader/debug/resource-loader-debug.h>
+#include "platform-capabilities.h"
+#include "image-operations.h"
+
+// EXTERNAL HEADERS
+#include <libexif/exif-data.h>
+#include <libexif/exif-loader.h>
+#include <libexif/exif-tag.h>
+#include <turbojpeg.h>
+#include <jpeglib.h>
+#include <cstring>
+#include <setjmp.h>
+
+namespace Dali
+{
+using Integration::Bitmap;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+  const unsigned DECODED_PIXEL_SIZE = 3;
+  const TJPF DECODED_PIXEL_LIBJPEG_TYPE = TJPF_RGB;
+
+  /** Transformations that can be applied to decoded pixels to respect exif orientation
+   *  codes in image headers */
+  enum JPGFORM_CODE
+  {
+    JPGFORM_NONE = 1, /* no transformation 0th-Row = top & 0th-Column = left */
+    JPGFORM_FLIP_H,   /* horizontal flip 0th-Row = top & 0th-Column = right */
+    JPGFORM_FLIP_V,   /* vertical flip   0th-Row = bottom & 0th-Column = right*/
+    JPGFORM_TRANSPOSE, /* transpose across UL-to-LR axis  0th-Row = bottom & 0th-Column = left*/
+    JPGFORM_TRANSVERSE,/* transpose across UR-to-LL axis  0th-Row = left   & 0th-Column = top*/
+    JPGFORM_ROT_90,    /* 90-degree clockwise rotation  0th-Row = right  & 0th-Column = top*/
+    JPGFORM_ROT_180,   /* 180-degree rotation  0th-Row = right  & 0th-Column = bottom*/
+    JPGFORM_ROT_270    /* 270-degree clockwise (or 90 ccw) 0th-Row = left  & 0th-Column = bottom*/
+  };
+
+  struct RGB888Type
+  {
+     char R;
+     char G;
+     char B;
+  };
+
+  /**
+   * @brief Error handling bookeeping for the JPEG Turbo library's
+   * setjmp/longjmp simulated exceptions.
+   */
+  struct JpegErrorState {
+    struct jpeg_error_mgr errorManager;
+    jmp_buf jumpBuffer;
+  };
+
+  /**
+   * @brief Called by the JPEG library when it hits an error.
+   * We jump out of the library so our loader code can return an error.
+   */
+  void  JpegErrorHandler ( j_common_ptr cinfo )
+  {
+    DALI_LOG_ERROR( "JpegErrorHandler(): libjpeg-turbo fatal error in JPEG decoding.\n" );
+    /* cinfo->err really points to a JpegErrorState struct, so coerce pointer */
+    JpegErrorState * myerr = reinterpret_cast<JpegErrorState *>( cinfo->err );
+
+    /* Return control to the setjmp point */
+    longjmp( myerr->jumpBuffer, 1 );
+  }
+
+  void JpegOutputMessageHandler( j_common_ptr cinfo )
+  {
+    /* Stop libjpeg from printing to stderr - Do Nothing */
+  }
+
+  /** Simple struct to ensure xif data is deleted. */
+  struct ExifAutoPtr
+  {
+    ExifAutoPtr( ExifData* data)
+    :mData( data )
+    {}
+
+    ~ExifAutoPtr()
+    {
+      exif_data_free( mData);
+    }
+    ExifData *mData;
+  };
+
+  /** simple class to enforce clean-up of JPEG structures. */
+  struct AutoJpg
+  {
+    AutoJpg(const tjhandle jpgHandle)
+    : mHnd(jpgHandle)
+    {
+    }
+
+    ~AutoJpg()
+    {
+      // clean up JPG resources
+      tjDestroy( mHnd );
+    }
+
+    tjhandle GetHandle() const
+    {
+      return mHnd ;
+    }
+
+  private:
+    AutoJpg( const AutoJpg& ); //< not defined
+    AutoJpg& operator= ( const AutoJpg& ); //< not defined
+
+    tjhandle mHnd;
+  }; // struct AutoJpg;
+
+  /** RAII wrapper to free memory allocated by the jpeg-turbo library. */
+  struct AutoJpgMem
+  {
+    AutoJpgMem(unsigned char * const tjMem)
+    : mTjMem(tjMem)
+    {
+    }
+
+    ~AutoJpgMem()
+    {
+      tjFree(mTjMem);
+    }
+
+    unsigned char * Get() const
+    {
+      return mTjMem;
+    }
+
+  private:
+    AutoJpgMem( const AutoJpgMem& ); //< not defined
+    AutoJpgMem& operator= ( const AutoJpgMem& ); //< not defined
+
+    unsigned char * const mTjMem;
+  };
+
+  // Workaround to avoid exceeding the maximum texture size
+  const int MAX_TEXTURE_WIDTH  = 4096;
+  const int MAX_TEXTURE_HEIGHT = 4096;
+
+} // namespace
+
+bool JpegRotate90 (unsigned char *buffer, int width, int height, int bpp);
+bool JpegRotate180(unsigned char *buffer, int width, int height, int bpp);
+bool JpegRotate270(unsigned char *buffer, int width, int height, int bpp);
+JPGFORM_CODE ConvertExifOrientation(ExifData* exifData);
+bool TransformSize( int requiredWidth, int requiredHeight,
+                    FittingMode::Type fittingMode, SamplingMode::Type samplingMode,
+                    JPGFORM_CODE transform,
+                    int& preXformImageWidth, int& preXformImageHeight,
+                    int& postXformImageWidth, int& postXformImageHeight );
+
+bool LoadJpegHeader( FILE *fp, unsigned int &width, unsigned int &height )
+{
+  // using libjpeg API to avoid having to read the whole file in a buffer
+  struct jpeg_decompress_struct cinfo;
+  struct JpegErrorState jerr;
+  cinfo.err = jpeg_std_error( &jerr.errorManager );
+
+  jerr.errorManager.output_message = JpegOutputMessageHandler;
+  jerr.errorManager.error_exit = JpegErrorHandler;
+
+  // On error exit from the JPEG lib, control will pass via JpegErrorHandler
+  // into this branch body for cleanup and error return:
+  if(setjmp(jerr.jumpBuffer))
+  {
+    jpeg_destroy_decompress(&cinfo);
+    return false;
+  }
+
+  jpeg_create_decompress( &cinfo );
+
+  jpeg_stdio_src( &cinfo, fp );
+
+  // Check header to see if it is  JPEG file
+  if( jpeg_read_header( &cinfo, TRUE ) != JPEG_HEADER_OK )
+  {
+    width = height = 0;
+    jpeg_destroy_decompress( &cinfo );
+    return false;
+  }
+
+  width = cinfo.image_width;
+  height = cinfo.image_height;
+
+  jpeg_destroy_decompress( &cinfo );
+  return true;
+}
+
+bool LoadBitmapFromJpeg( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  const int flags= 0;
+  FILE* const fp = input.file;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking to end of file\n");
+    return false;
+  }
+
+  long positionIndicator = ftell(fp);
+  unsigned int jpegBufferSize = 0u;
+  if( positionIndicator > -1L )
+  {
+    jpegBufferSize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == jpegBufferSize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+    return false;
+  }
+
+  std::vector<unsigned char> jpegBuffer(0);
+  try
+  {
+    jpegBuffer.reserve( jpegBufferSize );
+  }
+  catch(...)
+  {
+    DALI_LOG_ERROR( "Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U );
+    return false;
+  }
+  unsigned char * const jpegBufferPtr = &jpegBuffer[0];
+
+  // Pull the compressed JPEG image bytes out of a file and into memory:
+  if( fread( jpegBufferPtr, 1, jpegBufferSize, fp ) != jpegBufferSize )
+  {
+    DALI_LOG_WARNING("Error on image file read.");
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  // Allow early cancellation between the load and the decompress:
+  client.InterruptionPoint();
+
+  AutoJpg autoJpg(tjInitDecompress());
+
+  if(autoJpg.GetHandle() == NULL)
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    return false;
+  }
+
+  JPGFORM_CODE transform = JPGFORM_NONE;
+
+  if( input.reorientationRequested )
+  {
+    ExifAutoPtr exifData( exif_data_new_from_data(jpegBufferPtr, jpegBufferSize) );
+    if( exifData.mData )
+    {
+      transform = ConvertExifOrientation(exifData.mData);
+    }
+  }
+
+  // Push jpeg data in memory buffer through TurboJPEG decoder to make a raw pixel array:
+  int chrominanceSubsampling = -1;
+  int preXformImageWidth = 0, preXformImageHeight = 0;
+  if( tjDecompressHeader2( autoJpg.GetHandle(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling ) == -1 )
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
+  }
+
+  if(preXformImageWidth == 0 || preXformImageHeight == 0)
+  {
+    DALI_LOG_WARNING("Invalid Image!");
+    return false;
+  }
+
+  int requiredWidth  = input.scalingParameters.dimensions.GetWidth();
+  int requiredHeight = input.scalingParameters.dimensions.GetHeight();
+
+  // If transform is a 90 or 270 degree rotation, the logical width and height
+  // request from the client needs to be adjusted to account by effectively
+  // rotating that too, and the final width and height need to be swapped:
+  int postXformImageWidth = preXformImageWidth;
+  int postXformImageHeight = preXformImageHeight;
+
+
+  int scaledPreXformWidth   = preXformImageWidth;
+  int scaledPreXformHeight  = preXformImageHeight;
+  int scaledPostXformWidth  = postXformImageWidth;
+  int scaledPostXformHeight = postXformImageHeight;
+
+  TransformSize( requiredWidth, requiredHeight,
+                 input.scalingParameters.scalingMode,
+                 input.scalingParameters.samplingMode,
+                 transform,
+                 scaledPreXformWidth, scaledPreXformHeight,
+                 scaledPostXformWidth, scaledPostXformHeight );
+
+  // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
+
+  unsigned char * const bitmapPixelBuffer =  bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGB888, scaledPostXformWidth, scaledPostXformHeight);
+
+  // Allow early cancellation before decoding:
+  client.InterruptionPoint();
+
+  if( tjDecompress2( autoJpg.GetHandle(), jpegBufferPtr, jpegBufferSize, bitmapPixelBuffer, scaledPreXformWidth, 0, scaledPreXformHeight, DECODED_PIXEL_LIBJPEG_TYPE, flags ) == -1 )
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    return false;
+  }
+
+  const unsigned int  bufferWidth  = GetTextureDimension( scaledPreXformWidth );
+  const unsigned int  bufferHeight = GetTextureDimension( scaledPreXformHeight );
+
+  if( transform != JPGFORM_NONE )
+  {
+    // Allow early cancellation before shuffling pixels around on the CPU:
+    client.InterruptionPoint();
+  }
+
+  bool result = false;
+  switch(transform)
+  {
+    case JPGFORM_NONE:
+    {
+      result = true;
+      break;
+    }
+    // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
+    case JPGFORM_ROT_180:
+    {
+      result = JpegRotate180(bitmapPixelBuffer, bufferWidth, bufferHeight, DECODED_PIXEL_SIZE);
+      break;
+    }
+    case JPGFORM_ROT_270:
+    {
+      result = JpegRotate270(bitmapPixelBuffer, bufferWidth, bufferHeight, DECODED_PIXEL_SIZE);
+      break;
+    }
+    case JPGFORM_ROT_90:
+    {
+      result = JpegRotate90(bitmapPixelBuffer, bufferWidth, bufferHeight, DECODED_PIXEL_SIZE);
+      break;
+    }
+    /// Less-common orientation changes, since they don't correspond to a camera's
+    // physical orientation:
+    case JPGFORM_FLIP_H:
+    case JPGFORM_FLIP_V:
+    case JPGFORM_TRANSPOSE:
+    case JPGFORM_TRANSVERSE:
+    {
+      DALI_LOG_WARNING( "Unsupported JPEG Orientation transformation: %x.\n", transform );
+      break;
+    }
+  }
+  return result;
+}
+
+///@Todo: Move all these rotation functions to portable/image-operations and take "Jpeg" out of their names.
+bool JpegRotate90(unsigned char *buffer, int width, int height, int bpp)
+{
+  int  w, iw, ih, hw = 0;
+  int ix, iy = 0;
+  iw = width;
+  ih = height;
+  std::vector<unsigned char> data(width * height * bpp);
+  unsigned char *dataPtr = &data[0];
+  memcpy(dataPtr, buffer, width * height * bpp);
+  w = ih;
+  ih = iw;
+  iw = w;
+  hw = iw * ih;
+  hw = - hw - 1;
+  switch(bpp)
+  {
+    case 3:
+    {
+      RGB888Type* to = reinterpret_cast<RGB888Type*>(buffer) + iw - 1;
+      RGB888Type* from = reinterpret_cast<RGB888Type*>( dataPtr );
+
+      for(ix = iw; -- ix >= 0;)
+      {
+        for(iy = ih; -- iy >= 0; ++from )
+        {
+          *to = *from;
+          to += iw;
+        }
+        to += hw;
+      }
+      break;
+    }
+
+    default:
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool JpegRotate180(unsigned char *buffer, int width, int height, int bpp)
+{
+  int  ix, iw, ih, hw = 0;
+  iw = width;
+  ih = height;
+  hw = iw * ih;
+  ix = hw;
+
+  switch(bpp)
+  {
+    case 3:
+    {
+      RGB888Type tmp;
+      RGB888Type* to = reinterpret_cast<RGB888Type*>(buffer) ;
+      RGB888Type* from = reinterpret_cast<RGB888Type*>( buffer ) + hw - 1;
+      for(; --ix >= (hw / 2); ++to, --from)
+      {
+        tmp = *to;
+        *to = *from;
+        *from = tmp;
+      }
+      break;
+    }
+
+    default:
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool JpegRotate270(unsigned char *buffer, int width, int height, int bpp)
+{
+  int  w, iw, ih, hw = 0;
+  int ix, iy = 0;
+
+  iw = width;
+  ih = height;
+  std::vector<unsigned char> data(width * height * bpp);
+  unsigned char *dataPtr = &data[0];
+  memcpy(dataPtr, buffer, width * height * bpp);
+  w = ih;
+  ih = iw;
+  iw = w;
+  hw = iw * ih;
+
+  switch(bpp)
+  {
+    case 3:
+    {
+      RGB888Type* to = reinterpret_cast<RGB888Type*>(buffer) + hw  - iw;
+      RGB888Type* from = reinterpret_cast<RGB888Type*>( dataPtr );
+
+      w = -w;
+      hw =  hw + 1;
+      for(ix = iw; -- ix >= 0;)
+      {
+        for(iy = ih; -- iy >= 0;)
+        {
+          *to = *from;
+          from += 1;
+          to += w;
+        }
+        to += hw;
+      }
+      break;
+    }
+    default:
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool EncodeToJpeg( const unsigned char* const pixelBuffer, std::vector< unsigned char >& encodedPixels, const std::size_t width, const std::size_t height, const Pixel::Format pixelFormat, unsigned quality)
+{
+  if( !pixelBuffer )
+  {
+    DALI_LOG_ERROR("Null input buffer\n");
+    return false;
+  }
+
+  // Translate pixel format enum:
+  int jpegPixelFormat = -1;
+
+  switch( pixelFormat )
+  {
+    case Pixel::RGB888:
+    {
+      jpegPixelFormat = TJPF_RGB;
+      break;
+    }
+    case Pixel::RGBA8888:
+    {
+      // Ignore the alpha:
+      jpegPixelFormat = TJPF_RGBX;
+      break;
+    }
+    case Pixel::BGRA8888:
+    {
+      // Ignore the alpha:
+      jpegPixelFormat = TJPF_BGRX;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "Unsupported pixel format for encoding to JPEG." );
+      return false;
+    }
+  }
+
+  // Assert quality is in the documented allowable range of the jpeg-turbo lib:
+  DALI_ASSERT_DEBUG( quality >= 1 );
+  DALI_ASSERT_DEBUG( quality <= 100 );
+  if( quality < 1 )
+  {
+    quality = 1;
+  }
+  if( quality > 100 )
+  {
+    quality = 100;
+  }
+
+  // Initialise a JPEG codec:
+  AutoJpg autoJpg( tjInitCompress() );
+  {
+    if( autoJpg.GetHandle() == NULL )
+    {
+      DALI_LOG_ERROR( "JPEG Compressor init failed: %s\n", tjGetErrorStr() );
+      return false;
+    }
+
+    // Run the compressor:
+    unsigned char* dstBuffer = NULL;
+    unsigned long dstBufferSize = 0;
+    const int flags = 0;
+
+    if( tjCompress2( autoJpg.GetHandle(), const_cast<unsigned char*>(pixelBuffer), width, 0, height, jpegPixelFormat, &dstBuffer, &dstBufferSize, TJSAMP_444, quality, flags ) )
+    {
+      DALI_LOG_ERROR("JPEG Compression failed: %s\n", tjGetErrorStr());
+      return false;
+    }
+
+    // Safely wrap the jpeg codec's buffer in case we are about to throw, then
+    // save the pixels to a persistent buffer that we own and let our cleaner
+    // class clean up the buffer as it goes out of scope:
+    AutoJpgMem cleaner(dstBuffer);
+    encodedPixels.resize(dstBufferSize);
+    memcpy(&encodedPixels[0], dstBuffer, dstBufferSize);
+  }
+  return true;
+}
+
+
+JPGFORM_CODE ConvertExifOrientation(ExifData* exifData)
+{
+  JPGFORM_CODE transform = JPGFORM_NONE;
+  ExifEntry * const entry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
+  int orientation = 0;
+  if( entry )
+  {
+    orientation = exif_get_short(entry->data, exif_data_get_byte_order(entry->parent->parent));
+    switch( orientation )
+    {
+      case 1:
+      {
+        transform = JPGFORM_NONE;
+        break;
+      }
+      case 2:
+      {
+        transform = JPGFORM_FLIP_H;
+        break;
+      }
+      case 3:
+      {
+        transform = JPGFORM_FLIP_V;
+        break;
+      }
+      case 4:
+      {
+        transform = JPGFORM_TRANSPOSE;
+        break;
+      }
+      case 5:
+      {
+        transform = JPGFORM_TRANSVERSE;
+        break;
+      }
+      case 6:
+      {
+        transform = JPGFORM_ROT_90;
+        break;
+      }
+      case 7:
+      {
+        transform = JPGFORM_ROT_180;
+        break;
+      }
+      case 8:
+      {
+        transform = JPGFORM_ROT_270;
+        break;
+      }
+      default:
+      {
+        // Try to keep loading the file, but let app developer know there was something fishy:
+        DALI_LOG_WARNING( "Incorrect/Unknown Orientation setting found in EXIF header of JPEG image (%x). Orientation setting will be ignored.", entry );
+        break;
+      }
+    }
+  }
+  return transform;
+}
+
+bool TransformSize( int requiredWidth, int requiredHeight,
+                    FittingMode::Type fittingMode, SamplingMode::Type samplingMode,
+                    JPGFORM_CODE transform,
+                    int& preXformImageWidth, int& preXformImageHeight,
+                    int& postXformImageWidth, int& postXformImageHeight )
+{
+  bool success = true;
+
+  if( transform == JPGFORM_ROT_90 || transform == JPGFORM_ROT_270 )
+  {
+    std::swap( requiredWidth, requiredHeight );
+    std::swap( postXformImageWidth, postXformImageHeight );
+  }
+
+  // Apply the special rules for when there are one or two zeros in requested dimensions:
+  const ImageDimensions correctedDesired = Internal::Platform::CalculateDesiredDimensions( ImageDimensions( postXformImageWidth, postXformImageHeight), ImageDimensions( requiredWidth, requiredHeight ) );
+  requiredWidth = correctedDesired.GetWidth();
+  requiredHeight = correctedDesired.GetHeight();
+
+  // Rescale image during decode using one of the decoder's built-in rescaling
+  // ratios (expected to be powers of 2), keeping the final image at least as
+  // wide and high as was requested:
+
+  int numFactors = 0;
+  tjscalingfactor* factors = tjGetScalingFactors( &numFactors );
+  if( factors == NULL )
+  {
+    DALI_LOG_WARNING("TurboJpeg tjGetScalingFactors error!");
+    success = false;
+  }
+  else
+  {
+    // Internal jpeg downscaling is the same as our BOX_X sampling modes so only
+    // apply it if the application requested one of those:
+    // (use a switch case here so this code will fail to compile if other modes are added)
+    bool downscale = true;
+    switch( samplingMode )
+    {
+      case SamplingMode::BOX:
+      case SamplingMode::BOX_THEN_NEAREST:
+      case SamplingMode::BOX_THEN_LINEAR:
+      case SamplingMode::DONT_CARE:
+      {
+        downscale = true;
+        break;
+      }
+      case SamplingMode::NO_FILTER:
+      case SamplingMode::NEAREST:
+      case SamplingMode::LINEAR:
+      {
+        downscale = false;
+        break;
+      }
+    }
+
+    int scaleFactorIndex( 0 );
+    if( downscale )
+    {
+      // Find nearest supported scaling factor (factors are in sequential order, getting smaller)
+      for( int i = 1; i < numFactors; ++i )
+      {
+        bool widthLessRequired  = TJSCALED( postXformImageWidth,  factors[i]) < requiredWidth;
+        bool heightLessRequired = TJSCALED( postXformImageHeight, factors[i]) < requiredHeight;
+        switch( fittingMode )
+        {
+          // If either scaled dimension is smaller than the desired one, we were done at the last iteration:
+          case FittingMode::SCALE_TO_FILL:
+          {
+            if ( widthLessRequired || heightLessRequired )
+            {
+              break;
+            }
+          }
+          // If both dimensions are smaller than the desired one, we were done at the last iteration:
+          case FittingMode::SHRINK_TO_FIT:
+          {
+            if ( widthLessRequired && heightLessRequired )
+            {
+              break;
+            }
+          }
+          // If the width is smaller than the desired one, we were done at the last iteration:
+          case FittingMode::FIT_WIDTH:
+          {
+            if ( widthLessRequired )
+            {
+              break;
+            }
+          }
+          // If the width is smaller than the desired one, we were done at the last iteration:
+          case FittingMode::FIT_HEIGHT:
+          {
+            if ( heightLessRequired )
+            {
+              break;
+            }
+          }
+
+          // This factor stays is within our fitting mode constraint so remember it:
+          scaleFactorIndex = i;
+        }
+      }
+    }
+
+    // Regardless of requested size, downscale to avoid exceeding the maximum texture size:
+    for( int i = scaleFactorIndex; i < numFactors; ++i )
+    {
+      // Continue downscaling to below maximum texture size (if possible)
+      scaleFactorIndex = i;
+
+      if( TJSCALED(postXformImageWidth,  (factors[i])) < MAX_TEXTURE_WIDTH &&
+          TJSCALED(postXformImageHeight, (factors[i])) < MAX_TEXTURE_HEIGHT )
+      {
+        // Current scale-factor downscales to below maximum texture size
+        break;
+      }
+    }
+
+    // We have finally chosen the scale-factor, return width/height values
+    if( scaleFactorIndex > 0 )
+    {
+      preXformImageWidth   = TJSCALED(preXformImageWidth,   (factors[scaleFactorIndex]));
+      preXformImageHeight  = TJSCALED(preXformImageHeight,  (factors[scaleFactorIndex]));
+      postXformImageWidth  = TJSCALED(postXformImageWidth,  (factors[scaleFactorIndex]));
+      postXformImageHeight = TJSCALED(postXformImageHeight, (factors[scaleFactorIndex]));
+    }
+  }
+
+  return success;
+}
+
+ExifData* LoadExifData( FILE* fp )
+{
+  ExifData*     exifData=NULL;
+  ExifLoader*   exifLoader;
+  unsigned char dataBuffer[1024];
+
+  if( fseek( fp, 0, SEEK_SET ) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+  else
+  {
+    exifLoader = exif_loader_new ();
+
+    while( !feof(fp) )
+    {
+      int size = fread( dataBuffer, 1, sizeof( dataBuffer ), fp );
+      if( size <= 0 )
+      {
+        break;
+      }
+      if( ! exif_loader_write( exifLoader, dataBuffer, size ) )
+      {
+        break;
+      }
+    }
+
+    exifData = exif_loader_get_data( exifLoader );
+    exif_loader_unref( exifLoader );
+  }
+
+  return exifData;
+}
+
+bool LoadJpegHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  unsigned int requiredWidth  = input.scalingParameters.dimensions.GetWidth();
+  unsigned int requiredHeight = input.scalingParameters.dimensions.GetHeight();
+  FILE* const fp = input.file;
+
+  bool success = false;
+  if( requiredWidth == 0 && requiredHeight == 0 )
+  {
+    success = LoadJpegHeader( fp, width, height );
+  }
+  else
+  {
+    // Double check we get the same width/height from the header
+    unsigned int headerWidth;
+    unsigned int headerHeight;
+    if( LoadJpegHeader( fp, headerWidth, headerHeight ) )
+    {
+      JPGFORM_CODE transform = JPGFORM_NONE;
+
+      if( input.reorientationRequested )
+      {
+        ExifAutoPtr exifData( LoadExifData( fp ) );
+        if( exifData.mData )
+        {
+          transform = ConvertExifOrientation(exifData.mData);
+        }
+
+        int preXformImageWidth = headerWidth;
+        int preXformImageHeight = headerHeight;
+        int postXformImageWidth = headerWidth;
+        int postXformImageHeight = headerHeight;
+
+        success = TransformSize( requiredWidth, requiredHeight, input.scalingParameters.scalingMode, input.scalingParameters.samplingMode, transform, preXformImageWidth, preXformImageHeight, postXformImageWidth, postXformImageHeight );
+        if(success)
+        {
+          width = postXformImageWidth;
+          height = postXformImageHeight;
+        }
+      }
+      else
+      {
+        success = true;
+        width = headerWidth;
+        height = headerHeight;
+      }
+    }
+  }
+  return success;
+}
+
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/image-loaders/loader-jpeg.h b/platform-abstractions/tizen/image-loaders/loader-jpeg.h
new file mode 100644 (file)
index 0000000..c233fd5
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_JPEG_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_JPEG_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/images/pixel.h>
+#include "image-encoder.h"
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Jpeg
+{
+const unsigned char MAGIC_BYTE_1 = 0xFF;
+const unsigned char MAGIC_BYTE_2 = 0xD8;
+} // namespace Jpeg
+
+/**
+ * Loads the bitmap from an JPEG file.  This function checks the header first
+ * and if it is not a JPEG file, then it returns straight away.
+ * @param[in]  fp      Pointer to the Image file
+ * @param[in]  bitmap  The bitmap class where the decoded image will be stored
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromJpeg( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+/**
+ * Loads the header of a JPEG file and fills in the width and height appropriately.
+ * If the width and height are set on entry, it will set the width and height
+ * to the closest scaled size (exactly as will be loaded by LoadBitmapFromJpeg with the same
+ * attributes)
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[in/out]  width   Is set with the width of the image
+ * @param[in/out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadJpegHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+/**
+ * Encode raw pixel data to JPEG format.
+ * @param[in]  pixelBuffer    Pointer to raw pixel data to be encoded
+ * @param[out] encodedPixels  Encoded pixel data. Existing contents will be overwritten
+ * @param[in]  width          Image width
+ * @param[in]  height         Image height
+ * @param[in]  pixelFormat    Input pixel format (must be Pixel::RGB888)
+ * @param[in]  quality        JPEG quality on usual 1 to 100 scale.
+ */
+bool EncodeToJpeg(const unsigned char* pixelBuffer, std::vector< unsigned char >& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat, unsigned quality = 80);
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_LOADER_JPEG_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-ktx.cpp b/platform-abstractions/tizen/image-loaders/loader-ktx.cpp
new file mode 100755 (executable)
index 0000000..ca58304
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "loader-ktx.h"
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <stdint.h>
+#include <dali/public-api/common/compile-time-assert.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/public-api/images/pixel.h>
+
+namespace Dali
+{
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+/** Max width or height of an image. */
+const unsigned MAX_TEXTURE_DIMENSION = 4096;
+/** Max bytes of image data allowed. Not a precise number, just a sanity check. */
+const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION;
+/** We don't read any of this but limit it to a resonable amount in order to be
+ * friendly to files from random tools. */
+const unsigned MAX_BYTES_OF_KEYVALUE_DATA = 65536U;
+
+typedef uint8_t Byte;
+
+const Byte FileIdentifier[] = {
+   0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
+};
+
+/** The formats we support inside a KTX file container.
+ *  Currently only compressed formats are allowed as we'd rather
+ *  use a PNG or JPEG with their own compression for the general
+ *  cases. */
+enum KtxInternalFormat
+{
+  KTX_NOTEXIST = 0,
+  // GLES 3 Standard compressed formats (values same as in gl3.h):
+  KTX_COMPRESSED_R11_EAC                          = 0x9270,
+  KTX_COMPRESSED_SIGNED_R11_EAC                   = 0x9271,
+  KTX_COMPRESSED_RG11_EAC                         = 0x9272,
+  KTX_COMPRESSED_SIGNED_RG11_EAC                  = 0x9273,
+  KTX_COMPRESSED_RGB8_ETC2                        = 0x9274,
+  KTX_COMPRESSED_SRGB8_ETC2                       = 0x9275,
+  KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2    = 0x9276,
+  KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2   = 0x9277,
+  KTX_COMPRESSED_RGBA8_ETC2_EAC                   = 0x9278,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC            = 0x9279,
+
+  // GLES 2 EXTENSION FORMATS:
+  KTX_ETC1_RGB8_OES                               = 0x8D64,
+  KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG             = 0x8C00,
+  KTX_SENTINEL = ~0u,
+};
+
+const unsigned KtxInternalFormats[] =
+{
+  // GLES 3 Standard compressed formats:
+  KTX_COMPRESSED_R11_EAC,
+  KTX_COMPRESSED_SIGNED_R11_EAC,
+  KTX_COMPRESSED_RG11_EAC,
+  KTX_COMPRESSED_SIGNED_RG11_EAC,
+  KTX_COMPRESSED_RGB8_ETC2,
+  KTX_COMPRESSED_SRGB8_ETC2,
+  KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+  KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+  KTX_COMPRESSED_RGBA8_ETC2_EAC,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
+  // GLES 2 EXTENSION FORMATS:
+  KTX_ETC1_RGB8_OES,
+  KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
+  KTX_SENTINEL
+};
+
+struct KtxFileHeader
+{
+  Byte   identifier[12];
+  uint32_t endianness;
+  uint32_t glType;
+  uint32_t glTypeSize;
+  uint32_t glFormat;
+  uint32_t glInternalFormat;
+  uint32_t glBaseInternalFormat;
+  uint32_t pixelWidth;
+  uint32_t pixelHeight;
+  uint32_t pixelDepth;
+  uint32_t numberOfArrayElements;
+  uint32_t numberOfFaces;
+  uint32_t numberOfMipmapLevels;
+  uint32_t bytesOfKeyValueData;
+} __attribute__ ( (__packed__));
+// Packed attribute stops the structure from being aligned to compiler defaults
+// so we can be sure of reading the whole thing from file in one call to fread.
+
+/**
+ * Template function to read from the file directly into our structure.
+ * @param[in]  fp     The file to read from
+ * @param[out] header The structure we want to store our information in
+ * @return true, if read successful, false otherwise
+ */
+template<typename T>
+inline bool ReadHeader(FILE* fp, T& header)
+{
+  unsigned int readLength = sizeof(T);
+
+  // Load the information directly into our structure
+  if (fread((void*)&header, 1, readLength, fp) != readLength)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+/** Check whether the array passed in is the right size and matches the magic
+ *  values defined to be at the start of a KTX file by the specification.*/
+template<int BYTES_IN_SIGNATURE>
+bool CheckFileIdentifier(const Byte * const signature)
+{
+  const unsigned signatureSize = BYTES_IN_SIGNATURE;
+  const unsigned identifierSize = sizeof(FileIdentifier);
+  DALI_COMPILE_TIME_ASSERT(signatureSize == identifierSize);
+  const bool signatureGood = 0 == memcmp( signature, FileIdentifier, std::min( signatureSize, identifierSize ) );
+  return signatureGood;
+}
+
+/**
+ * @returns True if the argument is a GLES compressed texture format that we support.
+ */
+bool ValidInternalFormat(const unsigned format)
+{
+  unsigned candidateFormat = 0;
+  for(unsigned iFormat = 0; (candidateFormat = KtxInternalFormats[iFormat]) != KTX_SENTINEL; ++iFormat)
+  {
+    if(format == candidateFormat)
+    {
+      return true;
+    }
+  }
+  DALI_LOG_ERROR("Rejecting unsupported compressed format when loading compressed texture from KTX file: 0x%x.\n", format);
+  return false;
+}
+
+/**
+ * @returns The Pixel::Format Dali enum corresponding to the KTX internal format
+ *          passed in, or Pixel::INVALID_PIXEL_FORMAT if the format is not valid.
+ **/
+bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
+{
+  using namespace Dali::Pixel;
+  switch(ktxPixelFormat)
+  {
+    case KTX_COMPRESSED_R11_EAC:
+    {
+      format = Dali::Pixel::COMPRESSED_R11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SIGNED_R11_EAC:
+    {
+      format = COMPRESSED_SIGNED_R11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_RG11_EAC:
+    {
+      format = COMPRESSED_RG11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SIGNED_RG11_EAC:
+    {
+      format = COMPRESSED_SIGNED_RG11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_RGB8_ETC2:
+    {
+      format = COMPRESSED_RGB8_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ETC2:
+    {
+      format = COMPRESSED_SRGB8_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    {
+      format = COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    {
+      format = COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA8_ETC2_EAC:
+    {
+      format = COMPRESSED_RGBA8_ETC2_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
+      break;
+    }
+    // GLES 2 extension compressed formats:
+    case KTX_ETC1_RGB8_OES:
+    {
+      format = COMPRESSED_RGB8_ETC1;
+      break;
+    }
+    case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    {
+      format = COMPRESSED_RGB_PVRTC_4BPPV1;
+      break;
+    }
+
+    default:
+    {
+       return false;
+    }
+  }
+  return true;
+}
+
+bool LoadKtxHeader(FILE * const fp, unsigned int &width, unsigned int &height, KtxFileHeader &fileHeader)
+{
+  // Pull the bytes of the file header in as a block:
+  if ( !ReadHeader(fp, fileHeader) )
+  {
+    return false;
+  }
+  width = fileHeader.pixelWidth;
+  height = fileHeader.pixelHeight;
+
+  if ( width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION )
+  {
+    return false;
+  }
+
+  // Validate file header contents meet our minimal subset:
+  const bool signatureGood                            = CheckFileIdentifier<sizeof(fileHeader.identifier)>(fileHeader.identifier);
+  const bool fileEndiannessMatchesSystemEndianness    = fileHeader.endianness == 0x04030201; // Magic number from KTX spec.
+  const bool glTypeIsCompressed                       = fileHeader.glType == 0;
+  const bool glTypeSizeCompatibleWithCompressedTex    = fileHeader.glTypeSize == 1;
+  const bool glFormatCompatibleWithCompressedTex      = fileHeader.glFormat == 0;
+  const bool glInternalFormatIsSupportedCompressedTex = ValidInternalFormat(fileHeader.glInternalFormat);
+  // Ignore glBaseInternalFormat
+  const bool textureIsNot3D                           = fileHeader.pixelDepth == 0 || fileHeader.pixelDepth == 1;
+  const bool textureIsNotAnArray                      = fileHeader.numberOfArrayElements == 0 || fileHeader.numberOfArrayElements == 1;
+  const bool textureIsNotACubemap                     = fileHeader.numberOfFaces == 0 || fileHeader.numberOfFaces == 1;
+  const bool textureHasNoMipmapLevels                 = fileHeader.numberOfMipmapLevels == 0 || fileHeader.numberOfMipmapLevels == 1;
+  const bool keyValueDataNotTooLarge                  = fileHeader.bytesOfKeyValueData <= MAX_BYTES_OF_KEYVALUE_DATA;
+
+  const bool headerIsValid = signatureGood && fileEndiannessMatchesSystemEndianness && glTypeIsCompressed &&
+                           glTypeSizeCompatibleWithCompressedTex && glFormatCompatibleWithCompressedTex &&
+                           textureIsNot3D && textureIsNotAnArray && textureIsNotACubemap && textureHasNoMipmapLevels &&
+                           glInternalFormatIsSupportedCompressedTex & keyValueDataNotTooLarge;
+  if( !headerIsValid )
+  {
+     DALI_LOG_ERROR( "KTX file invalid or using unsupported features. Header tests: sig: %d, endian: %d, gl_type: %d, gl_type_size: %d, gl_format: %d, internal_format: %d, depth: %d, array: %d, faces: %d, mipmap: %d, vey-vals: %d.\n", 0+signatureGood, 0+fileEndiannessMatchesSystemEndianness, 0+glTypeIsCompressed, 0+glTypeSizeCompatibleWithCompressedTex, 0+glFormatCompatibleWithCompressedTex, 0+glInternalFormatIsSupportedCompressedTex, 0+textureIsNot3D, 0+textureIsNotAnArray, 0+textureIsNotACubemap, 0+textureHasNoMipmapLevels, 0+keyValueDataNotTooLarge);
+  }
+
+  // Warn if there is space wasted in the file:
+  if( fileHeader.bytesOfKeyValueData > 0U )
+  {
+    DALI_LOG_WARNING("Loading of KTX file with key/value header data requested. This should be stripped in application asset/resource build.\n");
+  }
+
+  return headerIsValid;
+}
+
+
+} // unnamed namespace
+
+// File loading API entry-point:
+bool LoadKtxHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  KtxFileHeader fileHeader;
+  FILE* const fp = input.file;
+
+  bool ret = LoadKtxHeader(fp, width, height, fileHeader);
+  return ret;
+}
+
+// File loading API entry-point:
+bool LoadBitmapFromKtx( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  DALI_COMPILE_TIME_ASSERT( sizeof(Byte) == 1);
+  DALI_COMPILE_TIME_ASSERT( sizeof(uint32_t) == 4);
+
+  FILE* const fp = input.file;
+  if( fp == NULL )
+  {
+    DALI_LOG_ERROR( "Null file handle passed to KTX compressed bitmap file loader.\n" );
+    return false;
+  }
+  KtxFileHeader fileHeader;
+
+  // Load the header info
+  unsigned int width, height;
+
+  if (!LoadKtxHeader(fp, width, height, fileHeader))
+  {
+      return false;
+  }
+
+  // Skip the key-values:
+  const long int imageSizeOffset = sizeof(KtxFileHeader) + fileHeader.bytesOfKeyValueData;
+  if(fseek(fp, imageSizeOffset, SEEK_SET))
+  {
+    DALI_LOG_ERROR( "Seek past key/vals in KTX compressed bitmap file failed.\n" );
+    return false;
+  }
+
+  // Load the size of the image data:
+  uint32_t imageByteCount = 0;
+  if (fread((void*)&imageByteCount, 1, 4, fp) != 4)
+  {
+    DALI_LOG_ERROR( "Read of image size failed.\n" );
+    return false;
+  }
+  // Sanity-check the image size:
+  if( imageByteCount > MAX_IMAGE_DATA_SIZE ||
+      // A compressed texture should certainly be less than 2 bytes per texel:
+      imageByteCount > width * height * 2)
+  {
+    DALI_LOG_ERROR( "KTX file with too-large image-data field.\n" );
+    return false;
+  }
+
+  Pixel::Format pixelFormat;
+  const bool pixelFormatKnown = ConvertPixelFormat(fileHeader.glInternalFormat, pixelFormat);
+  if(!pixelFormatKnown)
+  {
+    DALI_LOG_ERROR( "No internal pixel format supported for KTX file pixel format.\n" );
+    return false;
+  }
+
+  // Load up the image bytes:
+  PixelBuffer * const pixels = bitmap.GetCompressedProfile()->ReserveBufferOfSize( pixelFormat, width, height, (size_t) imageByteCount );
+  if(!pixels)
+  {
+    DALI_LOG_ERROR( "Unable to reserve a pixel buffer to load the requested bitmap into.\n" );
+    return false;
+  }
+  const size_t bytesRead = fread(pixels, 1, imageByteCount, fp);
+  if(bytesRead != imageByteCount)
+  {
+    DALI_LOG_ERROR( "Read of image pixel data failed.\n" );
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/image-loaders/loader-ktx.h b/platform-abstractions/tizen/image-loaders/loader-ktx.h
new file mode 100644 (file)
index 0000000..c521ad2
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_KTX_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_KTX_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Ktx
+{
+const unsigned char MAGIC_BYTE_1 = 0xAB;
+const unsigned char MAGIC_BYTE_2 = 0x4B;
+} // namespace Ktx
+
+/**
+ * Loads a compressed bitmap from a KTX file without decoding it.
+ * This function checks the header first
+ * and if it is not a KTX file, then it returns straight away.
+ * @param[in]  fp      Pointer to the Image file
+ * @param[in]  bitmap  The bitmap class where the decoded image will be stored
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @return  true if file loaded successfully, false otherwise
+ */
+bool LoadBitmapFromKtx( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+/**
+ * Loads the header of a KTX file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadKtxHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_LOADER_KTX_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-png.cpp b/platform-abstractions/tizen/image-loaders/loader-png.cpp
new file mode 100644 (file)
index 0000000..d6d6273
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "loader-png.h"
+
+#include <cstring>
+#include <cstdlib>
+
+#include <zlib.h>
+#include <png.h>
+
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/image.h>
+#include "dali/public-api/math/math-utils.h"
+#include "dali/public-api/math/vector2.h"
+#include "platform-capabilities.h"
+
+namespace Dali
+{
+
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+// simple class to enforce clean-up of PNG structures
+struct auto_png
+{
+  auto_png(png_structp& _png, png_infop& _info)
+  : png(_png),
+    info(_info)
+  {
+  }
+
+  ~auto_png()
+  {
+    if(NULL != png)
+    {
+      png_destroy_read_struct(&png, &info, NULL);
+    }
+  }
+
+  png_structp& png;
+  png_infop& info;
+}; // struct auto_png;
+
+bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
+{
+  png_byte header[8] = { 0 };
+
+  // Check header to see if it is a PNG file
+  size_t size = fread(header, 1, 8, fp);
+  if(size != 8)
+  {
+    return false;
+  }
+
+  if(png_sig_cmp(header, 0, 8))
+  {
+    return false;
+  }
+
+  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+  if(!png)
+  {
+    DALI_LOG_WARNING("Can't create PNG read structure\n");
+    return false;
+  }
+
+  info = png_create_info_struct(png);
+  if(!info)
+  {
+    DALI_LOG_WARNING("png_create_info_struct failed\n");
+    return false;
+  }
+
+  png_set_expand(png);
+
+  if(setjmp(png_jmpbuf(png)))
+  {
+    DALI_LOG_WARNING("error during png_init_io\n");
+    return false;
+  }
+
+  png_init_io(png, fp);
+  png_set_sig_bytes(png, 8);
+
+  // read image info
+  png_read_info(png, info);
+
+  // dimensions
+  width = png_get_image_width(png, info);
+  height = png_get_image_height(png, info);
+
+  return true;
+}
+
+} // namespace - anonymous
+
+bool LoadPngHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  png_structp png = NULL;
+  png_infop info = NULL;
+  auto_png autoPng(png, info);
+
+  bool success = LoadPngHeader( input.file, width, height, png, info );
+
+  return success;
+}
+
+bool LoadBitmapFromPng( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  png_structp png = NULL;
+  png_infop info = NULL;
+  auto_png autoPng(png, info);
+
+  /// @todo: consider parameters
+  unsigned int y;
+  unsigned int width, height;
+  unsigned char *pixels;
+  png_bytep *rows;
+  unsigned int bpp = 0; // bytes per pixel
+  bool valid = false;
+
+  // Load info from the header
+  if( !LoadPngHeader( input.file, width, height, png, info ) )
+  {
+    return false;
+  }
+
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+
+  // decide pixel format
+  unsigned int colordepth = png_get_bit_depth(png, info);
+
+  // Ask PNGLib to convert high precision images into something we can use:
+  if (colordepth == 16)
+  {
+    png_set_strip_16(png);
+    colordepth = 8;
+  }
+
+  png_byte colortype = png_get_color_type(png, info);
+
+  if(colortype == PNG_COLOR_TYPE_GRAY)
+  {
+    switch( colordepth )
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::L8;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
+  {
+    switch(colordepth)
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::LA88;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_RGB )
+  {
+    switch(colordepth)
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::RGB888;
+        valid = true;
+        break;
+      }
+      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
+      {
+        pixelFormat = Pixel::RGB565;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_RGBA)
+  {
+    switch(colordepth)
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::RGBA8888;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_PALETTE)
+  {
+    switch(colordepth)
+    {
+      case 2:
+      case 4:
+      case 8:
+      {
+        /* Expand paletted or RGB images with transparency to full alpha channels
+         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
+         */
+        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
+        {
+          pixelFormat = Pixel::RGBA8888;
+          valid = true;
+        }
+        else
+        {
+          pixelFormat = Pixel::RGB888;
+          png_set_packing(png);
+          png_set_packswap(png);
+          png_set_palette_to_rgb(png);
+          valid = true;
+        }
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  if( !valid )
+  {
+    DALI_LOG_WARNING( "Unsupported png format\n" );
+    return false;
+  }
+
+  // bytes per pixel
+  bpp = Pixel::GetBytesPerPixel(pixelFormat);
+
+  png_read_update_info(png, info);
+
+  if(setjmp(png_jmpbuf(png)))
+  {
+    DALI_LOG_WARNING("error during png_read_image\n");
+    return false;
+  }
+
+  unsigned int rowBytes = png_get_rowbytes(png, info);
+
+  unsigned int bufferWidth   = GetTextureDimension(width);
+  unsigned int bufferHeight  = GetTextureDimension(height);
+  unsigned int stride        = bufferWidth*bpp;
+
+  // not sure if this ever happens
+  if( rowBytes > stride )
+  {
+    stride = GetTextureDimension(rowBytes);
+    bufferWidth = stride / bpp;
+  }
+
+  // decode the whole image into bitmap buffer
+  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, width, height, bufferWidth, bufferHeight);
+
+  DALI_ASSERT_DEBUG(pixels);
+  rows = (png_bytep*) malloc(sizeof(png_bytep) * height);
+  for(y=0; y<height; y++)
+  {
+    rows[y] = (png_byte*) (pixels + y * stride);
+  }
+
+  // decode image
+  png_read_image(png, rows);
+
+  free(rows);
+
+  return true;
+}
+
+// simple class to enforce clean-up of PNG structures
+struct AutoPngWrite
+{
+  AutoPngWrite(png_structp& _png, png_infop& _info)
+  : png(_png),
+    info(_info)
+  {
+    DALI_ASSERT_DEBUG(&_png != 0 && &_info != 0);
+  }
+
+  ~AutoPngWrite()
+  {
+    if(NULL != png)
+    {
+      png_destroy_write_struct(&png, &info);
+    }
+  }
+
+  png_structp& png;
+  png_infop& info;
+}; // struct AutoPngWrite;
+
+namespace
+{
+  // Custom libpng write callbacks that buffer to a vector instead of a file:
+
+  /**
+   * extern "C" linkage is used because this is a callback that we pass to a C
+   * library which is part of the underlying platform and so potentially compiled
+   * as C rather than C++.
+   * @see http://stackoverflow.com/a/2594222
+   * */
+  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
+  {
+    using Dali::TizenPlatform::PngBuffer;
+    DALI_ASSERT_DEBUG(png_ptr && data);
+    if(!png_ptr || !data)
+    {
+      return;
+    }
+    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
+    try {
+      // Recover our buffer for writing into:
+      PngBuffer* const encoded_img = (PngBuffer*) png_get_io_ptr(png_ptr);
+      if(encoded_img)
+      {
+        const PngBuffer::size_type bufferSize = encoded_img->size();
+        encoded_img->resize(encoded_img->size() + length); //< Can throw OOM.
+        PngBuffer::value_type* const bufferBack = &((*encoded_img)[bufferSize]);
+        memcpy(bufferBack, data, length);
+      }
+      else
+      {
+        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.");
+      }
+    } catch(...)
+    {
+      DALI_LOG_ERROR("C++ Exception caught");
+    }
+  }
+
+  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
+  extern "C" void FlushData(png_structp png_ptr)
+  {
+#ifdef DEBUG_ENABLED
+    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
+#endif // DEBUG_ENABLED
+  }
+}
+
+/**
+ * Potential improvements:
+ * 1. Detect <= 256 colours and write in palette mode.
+ * 2. Detect grayscale (will early-out quickly for colour images).
+ * 3. Store colour space / gamma correction info related to the device screen?
+ *    http://www.libpng.org/pub/png/book/chapter10.html
+ * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
+ * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
+ * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
+ * 7. If caller asks for no compression, bypass libpng and blat raw data to
+ *    disk, topped and tailed with header/tail blocks.
+ */
+bool EncodeToPng( const unsigned char* const pixelBuffer, PngBuffer& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
+{
+  // Translate pixel format enum:
+  int pngPixelFormat = -1;
+  unsigned pixelBytes = 0;
+  bool rgbaOrder = true;
+
+  // Account for RGB versus BGR and presence of alpha in input pixels:
+  switch( pixelFormat )
+  {
+    case Pixel::RGB888:
+    {
+      pngPixelFormat = PNG_COLOR_TYPE_RGB;
+      pixelBytes = 3;
+      break;
+    }
+    case Pixel::BGRA8888:
+    {
+      rgbaOrder = false;
+      ///! No break: fall through:
+    }
+    case Pixel::RGBA8888:
+    {
+      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
+      pixelBytes = 4;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG." );
+      return false;
+    }
+  }
+
+  const int interlace = PNG_INTERLACE_NONE;
+
+  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if(!png_ptr)
+  {
+    return false;
+  }
+  /* Allocate/initialize the image information data.  REQUIRED */
+  png_infop info_ptr = png_create_info_struct( png_ptr );
+  if(!info_ptr)
+  {
+    png_destroy_write_struct(&png_ptr, NULL);
+    return false;
+  }
+
+  /* Set error handling.  REQUIRED if you aren't supplying your own
+   * error handling functions in the png_create_write_struct() call.
+   */
+  if(setjmp(png_jmpbuf(png_ptr)))
+  {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return false;
+  }
+
+  // Since we are going to write to memory instead of a file, lets provide
+  // libpng with a custom write function and ask it to pass back our
+  // std::vector buffer each time it calls back to flush data to "file":
+  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);
+
+  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
+  png_set_compression_level(png_ptr, Z_BEST_SPEED);
+  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.
+
+  // Explicitly limit the number of filters used per scanline to speed us up:
+  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
+       // PNG_FILTER_SUB   |
+       // PNG_FILTER_UP    |
+       // PNG_FILTER_AVE   |
+       // PNG_FILTER_PAETH |
+       // PNG_ALL_FILTERS);
+  // Play with Zlib parameters in optimisation phase:
+    // png_set_compression_mem_level(png_ptr, 8);
+    // png_set_compression_strategy(png_ptr,
+        // Z_DEFAULT_STRATEGY);
+    // png_set_compression_window_bits(png_ptr, 15);
+    // png_set_compression_method(png_ptr, 8);
+    // png_set_compression_buffer_size(png_ptr, 8192)
+
+  // Let lib_png know if the pixel bytes are in BGR(A) order:
+  if(!rgbaOrder)
+  {
+    png_set_bgr( png_ptr );
+  }
+
+  // Set the image information:
+  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+     pngPixelFormat, interlace,
+     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+  // Start to output the PNG data to our buffer:
+  png_write_info(png_ptr, info_ptr);
+
+  // Walk the rows:
+  const unsigned row_step = width * pixelBytes;
+  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
+  const png_bytep row_end = row_ptr + height * row_step;
+  for(; row_ptr < row_end; row_ptr += row_step)
+  {
+    png_write_row(png_ptr, row_ptr);
+  }
+
+  /* It is REQUIRED to call this to finish writing the rest of the file */
+  png_write_end(png_ptr, info_ptr);
+  /* Clean up after the write, and free any memory allocated */
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/image-loaders/loader-png.h b/platform-abstractions/tizen/image-loaders/loader-png.h
new file mode 100644 (file)
index 0000000..484226b
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_PNG_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_PNG_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/images/pixel.h>
+#include "image-encoder.h"
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Png
+{
+const unsigned char MAGIC_BYTE_1 = 0x89;
+const unsigned char MAGIC_BYTE_2 = 0x50;
+} // namespace Png
+
+/**
+ * Loads the bitmap from an PNG file.  This function checks the header first
+ * and if it is not a PNG file, then it returns straight away.
+ * @param[in]  fp      Pointer to the Image file
+ * @param[in]  bitmap  The bitmap class where the decoded image will be stored
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromPng( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+/**
+ * Loads the header of a PNG file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadPngHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+/**
+ * A bucket of bytes representing a PNG image.
+ **/
+typedef std::vector<unsigned char> PngBuffer;
+
+/**
+ * Encode raw pixel data to PNG format.
+ * @param[in]  pixelBuffer    Pointer to raw pixel data to be encoded
+ * @param[out] encodedPixels  Encoded pixel data. Existing contents will be overwritten
+ * @param[in]  width          Image width
+ * @param[in]  height         Image height
+ * @param[in]  pixelFormat    Input pixel format (must be Pixel::RGB888)
+ */
+bool EncodeToPng( const unsigned char* pixelBuffer, PngBuffer& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_LOADER_PNG_H__
diff --git a/platform-abstractions/tizen/image-loaders/loader-wbmp.cpp b/platform-abstractions/tizen/image-loaders/loader-wbmp.cpp
new file mode 100755 (executable)
index 0000000..8014bc6
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include "loader-wbmp.h"
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+using Integration::Bitmap;
+using Dali::Integration::PixelBuffer;
+namespace TizenPlatform
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOADER_WBMP");
+#endif
+
+#define IMG_MAX_SIZE 65536
+
+#define IMG_TOO_BIG(w, h) \
+        ((((unsigned long long)w) * ((unsigned long long)h)) >= \
+           ((1ULL << (29)) - 2048))
+
+
+//extract multiple bytes integer , and saved in *data
+int extractMultiByteInteger(unsigned int *data, void *map, size_t length, size_t *position)
+{
+  // the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
+  //,  a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
+  // The actual organisation of the image data depends on the image type
+  // for Ext Headers flag (7th bit), 1 = More will follow, 0 = Last octet
+  // so in the for loop, if(buf & 0x80 == 0), loop will be exited
+  int targetMultiByteInteger = 0, readBufCount;
+  unsigned char buf;
+
+  for (readBufCount = 0;;)
+  {
+    // readBufCount means the count that fetched data from map
+    // extractMultiByteInteger() is to fetch wbmp type , width, and height
+    // for wbmp type, when readBufCount == 1, buf = 0x00, it will exit the loop
+    // for width, it have 4 bytes, so when readBufCount == 4, it must exit the loop
+    // for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
+    // first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
+    // second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
+    if ((readBufCount ++) == 4)
+    {
+      return -1;
+    }
+    if (*position > length)
+    {
+      return -1;
+    }
+    buf = ((unsigned char *) map)[(*position)++];
+    targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
+
+    if ((buf & 0x80) == 0)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "position: %d, readBufCount: %d", *position, readBufCount);
+      break;
+    }
+  }
+  *data = targetMultiByteInteger;
+  return 0;
+}
+
+}// end unnamed namespace
+
+bool LoadBitmapFromWbmp( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  Dali::Vector<unsigned char> map;
+  Dali::Vector<unsigned char> surface;//unsigned int
+  PixelBuffer* pixels = NULL;
+  size_t position = 0;
+
+  unsigned int  w, h;
+  unsigned int type;
+  unsigned int line_length;
+  unsigned char *line = NULL;
+  int cur = 0, x, y;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  long positionIndicator = ftell(fp);
+
+  unsigned int fsize( 0u );
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    DALI_LOG_ERROR("Error: filesize is 0!\n");
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  if(fsize <= 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
+    return false;
+  }
+  if(fsize > 4096 * 4096 * 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP size is too large!\n");
+    return false;
+  }
+  map.Resize(fsize);
+
+  if(fread(&map[0], 1, fsize, fp) != fsize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!");
+    return false;
+  }
+
+  if (extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+
+  position++; /* skipping one byte */
+
+  if (extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+  if (extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+  if(type != 0)
+  {
+    DALI_LOG_ERROR("Unknown Format!\n");
+    return false;
+  }
+
+  if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+  {
+    return false;
+  }
+
+  surface.Resize(w* h );//(w * h * 4);
+  memset(&surface[0], 0, w * h ); // w * h * 4
+
+  line_length = (w + 7) >> 3;
+  for (y = 0; y < (int)h; y ++)
+  {
+    if (position + line_length > fsize)
+    {
+      return false;
+    }
+    line = &map[0] + position;
+    position += line_length;
+    for (x = 0; x < (int)w; x++)
+    {
+      int idx = x >> 3;
+      int offset = 1 << (0x07 - (x & 0x07));
+      if (line[idx] & offset)
+      {
+        surface[cur] = 0xff;//0xffffffff;
+      }
+      else
+      {
+        surface[cur] = 0x00;//0xff000000;
+      }
+      cur++;
+    }
+  }
+  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::L8, w, h);//Pixel::RGBA8888
+
+  memcpy(pixels, (unsigned char*)&surface[0], w * h );//w * h * 4
+
+  return true;
+}
+
+
+bool LoadWbmpHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  Dali::Vector<unsigned char> map;
+  size_t position = 0;
+
+  unsigned int  w, h;
+  unsigned int type;
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  long positionIndicator = ftell(fp);
+
+  unsigned int fsize( 0u );
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  if(fsize <= 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
+    return false;
+  }
+
+  // type(1 byte) + fixedheader(1 byte) + width(uint) + height(uint)
+  unsigned int headerSize = 1 + 1 + 4 + 4;// 8 + 8 + 32 + 32;
+  headerSize = std::min(headerSize, fsize);
+
+  map.Resize(headerSize);
+  if(fread(&map[0], 1, headerSize, fp) != headerSize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!");
+    return false;
+  }
+
+  if (extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: unable to read type!");
+    return false;
+  }
+  position++; /* skipping one byte */
+  if(type != 0)
+  {
+    DALI_LOG_ERROR("Error: unknown format!\n");
+    return false;
+  }
+  if (extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: can not read width!\n");
+    return false;
+  }
+  if (extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: can not read height!\n");
+    return false;
+  }
+
+  if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) )
+  {
+    DALI_LOG_ERROR("Error: file size is not supported!\n");
+    return false;
+  }
+
+  width = w;
+  height = h;
+  return true;
+}
+
+}
+}
diff --git a/platform-abstractions/tizen/image-loaders/loader-wbmp.h b/platform-abstractions/tizen/image-loaders/loader-wbmp.h
new file mode 100755 (executable)
index 0000000..30c94a5
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DALI_TIZEN_PLATFORM_LOADER_WBMP_H__
+#define __DALI_TIZEN_PLATFORM_LOADER_WBMP_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstdio>
+#include "image-loader-input.h"
+
+namespace Dali
+{
+
+namespace Integration
+{
+  class Bitmap;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+bool LoadBitmapFromWbmp( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap );
+
+bool LoadWbmpHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+}
+
+}
+#endif
diff --git a/platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.cpp b/platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.cpp
new file mode 100644 (file)
index 0000000..11f0a83
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "resource-loader-debug.h"
+
+#if defined(DEBUG_ENABLED)
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+using namespace Dali::Integration;
+
+/**
+ * Filter for resource loader debug. Change levels here to turn on debugging
+ */
+Debug::Filter* gLoaderFilter = Debug::Filter::New(Debug::Concise, false, "LOG_RESOURCE_LOADER");
+
+} //TizenPlatform
+} //Dali
+
+#endif
diff --git a/platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.h b/platform-abstractions/tizen/resource-loader/debug/resource-loader-debug.h
new file mode 100644 (file)
index 0000000..e8ebb96
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_LOADER_DEBUG_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_LOADER_DEBUG_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/debug.h>
+#if defined(DEBUG_ENABLED)
+
+#include <platform-abstractions/tizen/resource-loader/resource-loader.h>
+#include <dali/integration-api/resource-cache.h>
+
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+extern Debug::Filter* gLoaderFilter;
+
+} // TizenPlatform
+} // Dali
+
+#endif // defined(DEBUG_ENABLED)
+#endif //__DALI_TIZEN_PLATFORM_RESOURCE_LOADER_DEBUG_H__
diff --git a/platform-abstractions/tizen/resource-loader/image-encoder.h b/platform-abstractions/tizen/resource-loader/image-encoder.h
new file mode 100644 (file)
index 0000000..e6ec381
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H__
+#define __DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+/**
+ * Used file format
+ */
+enum FileFormat
+{
+  PNG_FORMAT,
+  JPG_FORMAT,
+  BMP_FORMAT,
+  GIF_FORMAT,
+  ICO_FORMAT,
+  INVALID_FORMAT
+};
+
+} // namespace Dali
+
+#endif //__DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H__
diff --git a/platform-abstractions/tizen/resource-loader/network/file-download.cpp b/platform-abstractions/tizen/resource-loader/network/file-download.cpp
new file mode 100755 (executable)
index 0000000..9f91eb6
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include "file-download.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <curl/curl.h>
+
+// INTERNAL INCLUDES
+#include "portable/file-closer.h"
+
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace // unnamed namespace
+{
+
+const int CONNECTION_TIMEOUT_SECONDS( 30L );
+const long VERBOSE_MODE = 0L;                // 0 == off, 1 == on
+const long CLOSE_CONNECTION_ON_ERROR = 1L;   // 0 == off, 1 == on
+const long EXCLUDE_HEADER = 0L;
+const long INCLUDE_HEADER = 1L;
+const long INCLUDE_BODY = 0L;
+const long EXCLUDE_BODY = 1L;
+
+void ConfigureCurlOptions( CURL* curl_handle, const std::string& url )
+{
+  curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
+  curl_easy_setopt( curl_handle, CURLOPT_VERBOSE, VERBOSE_MODE );
+
+  // CURLOPT_FAILONERROR is not fail-safe especially when authentication is involved ( see manual )
+  curl_easy_setopt( curl_handle, CURLOPT_FAILONERROR, CLOSE_CONNECTION_ON_ERROR );
+  curl_easy_setopt( curl_handle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS );
+  curl_easy_setopt( curl_handle, CURLOPT_HEADER, INCLUDE_HEADER );
+  curl_easy_setopt( curl_handle, CURLOPT_NOBODY, EXCLUDE_BODY );
+}
+
+// Without a write function or a buffer (file descriptor) to write to, curl will pump out
+// header/body contents to stdout
+size_t DummyWrite(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+  return size * nmemb;
+}
+
+
+bool DownloadFile( CURL* curl_handle,
+                   const std::string& url,
+                   Dali::Vector<uint8_t>& dataBuffer,
+                   size_t& dataSize,
+                   size_t maximumAllowedSizeBytes )
+{
+  CURLcode res( CURLE_OK );
+  double size(0);
+
+  // setup curl to download just the header so we can extract the content length
+  ConfigureCurlOptions( curl_handle, url );
+
+  curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, DummyWrite);
+
+  // perform the request to get the header
+  res = curl_easy_perform( curl_handle );
+
+  if( res != CURLE_OK)
+  {
+    DALI_LOG_WARNING( "Failed to download http header for \"%s\" with error code %d\n", url.c_str(), res );
+    return false;
+  }
+
+  // get the content length, -1 == size is not known
+  curl_easy_getinfo( curl_handle,CURLINFO_CONTENT_LENGTH_DOWNLOAD , &size );
+
+  if( size < 1 )
+  {
+    DALI_LOG_WARNING( "Header missing content length \"%s\" \n", url.c_str() );
+    return false;
+  }
+  if( size >= maximumAllowedSizeBytes )
+  {
+    DALI_LOG_WARNING( "File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str() );
+    return false;
+  }
+
+  dataSize = static_cast<size_t>( size );
+
+  dataBuffer.Resize( dataSize );
+
+  // create
+  Dali::Internal::Platform::FileCloser fileCloser( static_cast<void*>(&dataBuffer[0]), dataSize, "wb" );
+  FILE* dataBufferFilePointer = fileCloser.GetFile();
+  if( NULL != dataBufferFilePointer )
+  {
+    // we only want the body which contains the file data
+    curl_easy_setopt( curl_handle, CURLOPT_HEADER, EXCLUDE_HEADER );
+    curl_easy_setopt( curl_handle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+    // disable the write callback, and get curl to write directly into our data buffer
+    curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, NULL );
+    curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, dataBufferFilePointer );
+
+    // synchronous request of the body data
+    res = curl_easy_perform( curl_handle );
+
+    if( CURLE_OK != res )
+    {
+      DALI_LOG_WARNING( "Failed to download image file \"%s\" with error code %d\n", url.c_str(), res );
+      return false;
+    }
+  }
+  return true;
+}
+} // unnamed namespace
+
+
+
+bool Network::DownloadRemoteFileIntoMemory( const std::string& url,
+                                            Dali::Vector<uint8_t>& dataBuffer,
+                                            size_t& dataSize,
+                                            size_t maximumAllowedSizeBytes )
+{
+  if( url.empty() )
+  {
+    DALI_LOG_WARNING("empty url requested \n");
+    return false;
+  }
+
+  // start a libcurl easy session, this internally calls curl_global_init, if we ever have more than one download
+  // thread we need to explicity call curl_global_init() on startup from a single thread.
+
+  CURL* curl_handle = curl_easy_init();
+
+  bool result = DownloadFile( curl_handle, url, dataBuffer,  dataSize, maximumAllowedSizeBytes);
+
+  // clean up session
+  curl_easy_cleanup( curl_handle );
+
+  return result;
+}
+
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/resource-loader/network/file-download.h b/platform-abstractions/tizen/resource-loader/network/file-download.h
new file mode 100644 (file)
index 0000000..0d31953
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H__
+#define __DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <string>
+#include <stdint.h> // uint8
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * Download a requested file into a memory buffer.
+ * Threading notes: This function can be called from multiple threads, however l
+ * we must explicitly call curl_global_init() from a single thread before using curl
+ * as the global function calls are not thread safe.
+ *
+ * @param[in] url The requested file url
+ * @param[out] dataBuffer  A memory buffer object to be written with downloaded file data.
+ * @param[out] dataSize  The size of the memory buffer.
+ * @param[in] maximumAllowedSize The maxmimum allowed file size in bytes to download. E.g. for an Image file this may be 50 MB
+ * @return true on success, false on failure
+ *
+ */
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+                                   Dali::Vector<uint8_t>& dataBuffer,
+                                   size_t& dataSize,
+                                   size_t maximumAllowedSizeBytes );
+
+} // namespace Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
diff --git a/platform-abstractions/tizen/resource-loader/network/http-utils.cpp b/platform-abstractions/tizen/resource-loader/network/http-utils.cpp
new file mode 100644 (file)
index 0000000..517dfbd
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "http-utils.h"
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int MIN_HTTP_URL_LENGTH = 12; // assume we have a least http://xx/yy
+const char HTTP_URL[] = "http://";
+const char HTTPS_URL[] = "https://";
+}
+
+bool Network::IsHttpUrl( const std::string& path )
+{
+ if( path.size() <= MIN_HTTP_URL_LENGTH )
+ {
+   return false;
+ }
+
+ if( ( strncasecmp( path.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) == 0 )  ||
+     ( strncasecmp( path.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) == 0 ) )
+ {
+   return true;
+ }
+
+ return false;
+}
+
+} // TizenPlatform
+
+} // Dali
diff --git a/platform-abstractions/tizen/resource-loader/network/http-utils.h b/platform-abstractions/tizen/resource-loader/network/http-utils.h
new file mode 100644 (file)
index 0000000..e7d225c
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
+#define __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <string>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * @brief Tests if a string starts with either http:// or https://
+ * @param[in] path string
+ * @return true if the path is a http url
+ */
+bool IsHttpUrl( const std::string& path );
+
+} // Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_NETWORK_UTILS_H__
diff --git a/platform-abstractions/tizen/resource-loader/platform-capabilities.h b/platform-abstractions/tizen/resource-loader/platform-capabilities.h
new file mode 100644 (file)
index 0000000..aba3dbd
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __DALI_TIZEN_PLATFORM_CAPABILITIES_H__
+#define __DALI_TIZEN_PLATFORM_CAPABILITIES_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/math/math-utils.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+/**
+ * Returns true if non power of two textures are supported.
+ */
+inline bool SupportsNonPowerOfTwoTextures()
+{
+#ifdef NON_POWER_OF_TWO_TEXTURES
+  return true; // All current devices and desktop builds have NPOT
+#else
+#error "NPOT are standard in GLES 2.0 if mipmaps are not used, they are standard with mipmaps and no restrictions in GLES 3.0, requiring them simplifies image handling code."
+  return false;
+#endif
+}
+
+/**
+ * Returns the size that a textures dimension should have for a specific image size.
+ */
+inline unsigned int GetTextureDimension( unsigned int size )
+{
+#ifdef NON_POWER_OF_TWO_TEXTURES
+  return size;
+#else
+#error "NPOT are standard in GLES 2.0 if mipmaps are not used, they are standard with mipmaps and no restrictions in GLES 3.0, requiring them simplifies image handling code."
+  return NextPowerOfTwo( size );
+#endif
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_CAPABILITIES_H__
diff --git a/platform-abstractions/tizen/resource-loader/resource-bitmap-requester.cpp b/platform-abstractions/tizen/resource-loader/resource-bitmap-requester.cpp
new file mode 100644 (file)
index 0000000..67da901
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "resource-bitmap-requester.h"
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/resource-cache.h>
+
+// INTERNAL INCLUDES
+#include "network/file-download.h"
+#include "network/http-utils.h"
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace
+{
+enum ResourceScheme
+{
+  FILE_SYSTEM_RESOURCE,
+  NETWORK_RESOURCE
+};
+}// unnamed namespace
+
+ResourceBitmapRequester::ResourceBitmapRequester( ResourceLoader& resourceLoader )
+: ResourceRequesterBase( resourceLoader ),
+  mThreadImageLocal( NULL ),
+  mThreadImageRemote( NULL )
+{
+}
+
+ResourceBitmapRequester::~ResourceBitmapRequester()
+{
+  delete mThreadImageLocal;
+  delete mThreadImageRemote;
+}
+
+void ResourceBitmapRequester::Pause()
+{
+  if( mThreadImageLocal )
+  {
+    mThreadImageLocal->Pause();
+  }
+  if( mThreadImageRemote )
+  {
+    mThreadImageRemote->Pause();
+  }
+}
+
+void ResourceBitmapRequester::Resume()
+{
+  if( mThreadImageLocal )
+  {
+    mThreadImageLocal->Resume();
+  }
+  if( mThreadImageRemote )
+  {
+    mThreadImageRemote->Resume();
+  }
+}
+
+void ResourceBitmapRequester::LoadResource( Integration::ResourceRequest& request )
+{
+  DALI_ASSERT_DEBUG( (0 != dynamic_cast<BitmapResourceType*>(request.GetType())) && "Only requsts for bitmap resources can ever be routed to ResourceBitmapRequester.\n");
+  BitmapResourceType* resType = static_cast<BitmapResourceType*>(request.GetType());
+  if( !resType )
+  {
+    return;
+  }
+
+  // Work out what thread to decode / load the image on:
+  ResourceScheme scheme( FILE_SYSTEM_RESOURCE );
+
+  // Work out if the resource is in memory, a file, or in a remote server:
+  ResourceThreadBase::RequestType requestType;
+
+  // if resource exists already, then it just needs decoding
+  if( request.GetResource().Get() )
+  {
+    requestType = ResourceThreadBase::RequestDecode;
+  }
+  else
+  {
+    const std::string& resourcePath = request.GetPath();
+    if( Network::IsHttpUrl( resourcePath) )
+    {
+      requestType = ResourceThreadBase::RequestDownload;
+      scheme = NETWORK_RESOURCE;
+    }
+    else
+    {
+      requestType = ResourceThreadBase::RequestLoad;
+    }
+  }
+
+  // Dispatch the job to the right thread
+  // lazily create the thread
+  if( scheme ==  FILE_SYSTEM_RESOURCE )
+  {
+    if( !mThreadImageLocal )
+    {
+      mThreadImageLocal = new ResourceThreadImage( mResourceLoader );
+    }
+    mThreadImageLocal->AddRequest( request, requestType );
+  }
+  else
+  {
+    if( !mThreadImageRemote )
+    {
+      mThreadImageRemote = new ResourceThreadImage( mResourceLoader );
+    }
+    mThreadImageRemote->AddRequest( request, requestType );
+  }
+}
+
+Integration::LoadStatus ResourceBitmapRequester::LoadFurtherResources( Integration::ResourceRequest& request, LoadedResource partialResource )
+{
+  // Nothing to do
+  return RESOURCE_COMPLETELY_LOADED;
+}
+
+void ResourceBitmapRequester::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
+{
+  if( mThreadImageLocal )
+  {
+    mThreadImageLocal->CancelRequest(id);
+  }
+  if( mThreadImageRemote )
+  {
+    mThreadImageRemote->CancelRequest(id);
+  }
+}
+
+} // TizenPlatform
+} // Dali
diff --git a/platform-abstractions/tizen/resource-loader/resource-bitmap-requester.h b/platform-abstractions/tizen/resource-loader/resource-bitmap-requester.h
new file mode 100644 (file)
index 0000000..7f59e6b
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_BITMAP_REQUESTER_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_BITMAP_REQUESTER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "resource-requester-base.h"
+#include "resource-thread-image.h"
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+/**
+ * Class to own request threads and manage resource requests for bitmaps
+ */
+class ResourceBitmapRequester : public ResourceRequesterBase
+{
+public:
+  /**
+   * Constructor
+   * @param[in] resourceLoader The resource loader with which to communicate results
+   */
+  ResourceBitmapRequester( ResourceLoader& resourceLoader );
+
+  /**
+   * Destructor
+   */
+  virtual ~ResourceBitmapRequester();
+
+  /**
+   * @copydoc ResourceRequester::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc ResourceRequester::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc ResourceRequester::LoadResource()
+   */
+  virtual void LoadResource( Integration::ResourceRequest& request );
+
+  /**
+   * @copydoc ResourceRequester::LoadFurtherResources()
+   */
+  virtual Integration::LoadStatus LoadFurtherResources( Integration::ResourceRequest& request, LoadedResource partialResource );
+
+  /**
+   * @copydoc ResourceRequester::CancelLoad()
+   */
+  virtual void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId);
+
+private:
+  ResourceThreadImage*          mThreadImageLocal;      ///< Image loader thread object to load images in local machine
+  ResourceThreadImage*          mThreadImageRemote;     ///< Image loader thread object to download images in remote http server
+};
+
+} // TizenPlatform
+} // Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_BITMAP_REQUESTER_H__
diff --git a/platform-abstractions/tizen/resource-loader/resource-loader.cpp b/platform-abstractions/tizen/resource-loader/resource-loader.cpp
new file mode 100755 (executable)
index 0000000..89328aa
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "resource-loader.h"
+
+// EXTERNAL HEADERS
+#include <boost/thread.hpp>
+#include <iostream>
+#include <fstream>
+#include <queue>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/resource-cache.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/devel-api/common/set-wrapper.h>
+#include <dali/public-api/math/vector2.h>
+#include "resource-requester-base.h"
+#include "resource-bitmap-requester.h"
+#include "debug/resource-loader-debug.h"
+
+
+/**
+ * A macro to expand an argument to a compile time constant string literal.
+ * Wrapping the stringify in an outer macro, means that any macro passed as
+ * "x" will be expanded before being turned into a string.
+ * Use this for example to turn the current line number into a string:
+ *   puts("The current line number is " DALI_TO_STRING(__LINE__) ".");
+ */
+#define DALI_TO_STRING_INNER(x) #x
+#define DALI_TO_STRING(x) DALI_TO_STRING_INNER(x)
+
+using namespace Dali::Integration;
+using boost::mutex;
+using boost::unique_lock;
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+} // unnamed namespace
+
+
+struct ResourceLoader::ResourceLoaderImpl
+{
+  typedef std::pair<ResourceId, ResourceRequest>  RequestStorePair;
+  typedef std::map<ResourceId, ResourceRequest>   RequestStore;
+  typedef RequestStore::iterator                  RequestStoreIter;
+
+  typedef std::queue<LoadedResource> LoadedQueue;
+  typedef std::queue<FailedResource> FailedQueue;
+
+  typedef std::pair<ResourceTypeId, ResourceRequesterBase*> RequestHandlerPair;
+  typedef std::map<ResourceTypeId,  ResourceRequesterBase*> RequestHandlers;
+  typedef RequestHandlers::iterator                         RequestHandlersIter;
+
+  boost::mutex mQueueMutex;             ///< used to synchronize access to mLoadedQueue and mFailedQueue
+  LoadedQueue  mPartiallyLoadedQueue;   ///< Partially complete load requests notifications are stored here until fetched by core
+  LoadedQueue  mLoadedQueue;            ///< Completed load requests notifications are stored here until fetched by core
+  FailedQueue  mFailedLoads;            ///< Failed load request notifications are stored here until fetched by core
+
+  RequestHandlers mRequestHandlers;
+  RequestStore mStoredRequests;         ///< Used to store load requests until loading is completed
+
+  ResourceLoaderImpl( ResourceLoader* loader )
+  {
+    mRequestHandlers.insert(std::make_pair(ResourceBitmap, new ResourceBitmapRequester(*loader)));
+  }
+
+  ~ResourceLoaderImpl()
+  {
+    // Delete resource handlers
+    for( RequestHandlersIter it = mRequestHandlers.begin(); it != mRequestHandlers.end(); ++it )
+    {
+      ResourceRequesterBase* requestBase = it->second;
+      delete requestBase;
+    }
+  }
+
+  void Pause()
+  {
+    // Pause all the request handlers:
+    for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end;  ++it )
+    {
+      ResourceRequesterBase * const requester = it->second;
+      if( requester )
+      {
+        requester->Pause();
+      }
+    }
+  }
+
+  void Resume()
+  {
+    // Wake up all the request handlers:
+    for( RequestHandlersIter it = mRequestHandlers.begin(), end = mRequestHandlers.end(); it != end;  ++it )
+    {
+      ResourceRequesterBase * const requester = it->second;
+      if( requester )
+      {
+        requester->Resume();
+      }
+    }
+  }
+
+  ResourceRequesterBase* GetRequester(ResourceTypeId typeId)
+  {
+    ResourceRequesterBase* requestHandler = NULL;
+    RequestHandlersIter iter = mRequestHandlers.find(typeId);
+    if(iter != mRequestHandlers.end())
+    {
+      requestHandler = iter->second;
+    }
+    DALI_ASSERT_DEBUG(requestHandler && "All resource types should have a requester defined for them.");
+    return requestHandler;
+  }
+
+  void LoadResource(const ResourceRequest& request)
+  {
+    // Store resource request for partial loaders. Will get cleaned up after load complete has finished
+    StoreRequest(request);
+
+    ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
+    if( requester )
+    {
+      ResourceRequest* storedRequest = GetRequest(request.GetId());
+      if( storedRequest != NULL )
+      {
+        requester->LoadResource(*storedRequest); // Pass in stored request
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Unknown resource type (%u) with path \"%s\" in load request.\n", request.GetType()->id, request.GetPath().c_str() );
+      DALI_ASSERT_DEBUG( 0 == "Unknown resource type in load request at " __FILE__ ", line " DALI_TO_STRING(__LINE__) ".\n" );
+    }
+  }
+
+  void CancelLoad(ResourceId id, ResourceTypeId typeId)
+  {
+    ResourceRequesterBase* requester = GetRequester(typeId);
+    if( requester )
+    {
+      requester->CancelLoad( id, typeId );
+    }
+    ClearRequest( id );
+  }
+
+  LoadStatus LoadFurtherResources( LoadedResource partialResource )
+  {
+    LoadStatus loadStatus = RESOURCE_LOADING;
+    RequestStoreIter iter = mStoredRequests.find(partialResource.id);
+
+    if( mStoredRequests.end() != iter ) // else cancelled. Ignore response
+    {
+      ResourceRequest& request = iter->second;
+      ResourceRequesterBase* requester = GetRequester(request.GetType()->id);
+      if( requester )
+      {
+        loadStatus = requester->LoadFurtherResources( request, partialResource );
+      }
+
+      DALI_LOG_INFO(gLoaderFilter, Debug::General, "ResourceLoader::LoadFurtherResources( ID:%u complete: %s)\n",  request.GetId(), loadStatus==RESOURCE_LOADING?"Loading":loadStatus==RESOURCE_PARTIALLY_LOADED?"PARTIAL":"COMPLETE" );
+    }
+
+    if( loadStatus == RESOURCE_COMPLETELY_LOADED )
+    {
+      ClearRequest( partialResource.id );
+    }
+
+    return loadStatus;
+  }
+
+  bool IsLoading()
+  {
+    // TODO - not used - remove?
+    DALI_ASSERT_DEBUG( 0 == "IsLoading() Is not implemented so don't call it." );
+    return true;
+  }
+
+  void GetResources(ResourceCache& cache)
+  {
+    // Fill the resource cache
+
+    unique_lock<mutex> lock(mQueueMutex);
+
+    // iterate through the partially loaded resources
+    while (!mPartiallyLoadedQueue.empty())
+    {
+      LoadedResource loaded( mPartiallyLoadedQueue.front() );
+      mPartiallyLoadedQueue.pop();
+      LoadStatus loadStatus = LoadFurtherResources( loaded );
+      cache.LoadResponse( loaded.id, loaded.type, loaded.resource, loadStatus );
+    }
+
+    // iterate through the successfully loaded resources
+    while (!mLoadedQueue.empty())
+    {
+      LoadedResource loaded( mLoadedQueue.front() );
+      mLoadedQueue.pop();
+      ClearRequest( loaded.id );
+      cache.LoadResponse( loaded.id, loaded.type, loaded.resource, RESOURCE_COMPLETELY_LOADED );
+    }
+
+    // iterate through the resources which failed to load
+    while (!mFailedLoads.empty())
+    {
+      FailedResource failed(mFailedLoads.front());
+      mFailedLoads.pop();
+      ClearRequest(failed.id);
+      cache.LoadFailed(failed.id, failed.failureType);
+    }
+  }
+
+  void AddPartiallyLoadedResource( LoadedResource& resource)
+  {
+    // Lock the LoadedQueue to store the loaded resource
+    unique_lock<mutex> lock(mQueueMutex);
+
+    mPartiallyLoadedQueue.push( resource );
+  }
+
+  void AddLoadedResource(LoadedResource& resource)
+  {
+    // Lock the LoadedQueue to store the loaded resource
+    unique_lock<mutex> lock(mQueueMutex);
+
+    mLoadedQueue.push( resource );
+  }
+
+  void AddFailedLoad(FailedResource& resource)
+  {
+    // Lock the FailedQueue to store the failed resource information
+    unique_lock<mutex> lock(mQueueMutex);
+
+    mFailedLoads.push(resource);
+  }
+
+  void StoreRequest( const ResourceRequest& request )
+  {
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: StoreRequest(id:%u)\n", request.GetId());
+    mStoredRequests.insert( RequestStorePair( request.GetId(), request ) ); // copy request as value type
+  }
+
+  ResourceRequest* GetRequest( ResourceId id )
+  {
+    ResourceRequest* found(NULL);
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: GetRequest(id:%u)\n", id);
+    RequestStoreIter iter = mStoredRequests.find( id );
+    if( mStoredRequests.end() != iter )
+    {
+      found = &iter->second;
+    }
+    return found;
+  }
+
+  void ClearRequest( ResourceId resourceId )
+  {
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader: ClearRequest(id:%u)\n", resourceId);
+    RequestStoreIter iter = mStoredRequests.find( resourceId );
+    if( mStoredRequests.end() != iter ) // Can't assert here - cancel load may cross with load failed
+    {
+      mStoredRequests.erase( iter );
+    }
+  }
+};
+
+/********************************************************************************/
+/****************************   RESOURCE LOADER METHODS  ************************/
+/********************************************************************************/
+ResourceLoader::ResourceLoader()
+: mTerminateThread(0)
+{
+  mImpl = new ResourceLoaderImpl( this );
+}
+
+ResourceLoader::~ResourceLoader()
+{
+  // Flag that the ResourceLoader is exiting
+  (void)__sync_or_and_fetch( &mTerminateThread, -1 );
+
+  delete mImpl;
+}
+
+void ResourceLoader::Pause()
+{
+  mImpl->Pause();
+}
+
+void ResourceLoader::Resume()
+{
+  mImpl->Resume();
+}
+
+bool ResourceLoader::IsTerminating()
+{
+  return __sync_fetch_and_or( &mTerminateThread, 0 );
+}
+
+void ResourceLoader::GetResources(ResourceCache& cache)
+{
+  mImpl->GetResources( cache );
+}
+
+/********************************************************************************/
+/**************************   CALLED FROM LOADER THREADS   **********************/
+/********************************************************************************/
+
+void ResourceLoader::AddPartiallyLoadedResource( LoadedResource& resource)
+{
+  mImpl->AddPartiallyLoadedResource( resource );
+}
+
+void ResourceLoader::AddLoadedResource(LoadedResource& resource)
+{
+  mImpl->AddLoadedResource( resource );
+}
+
+void ResourceLoader::AddFailedLoad(FailedResource& resource)
+{
+  mImpl->AddFailedLoad( resource );
+}
+
+/********************************************************************************/
+/*********************   CALLED FROM PLATFORM ABSTRACTION  **********************/
+/********************************************************************************/
+
+void ResourceLoader::LoadResource(const ResourceRequest& request)
+{
+  mImpl->LoadResource(request);
+}
+
+void ResourceLoader::CancelLoad(ResourceId id, ResourceTypeId typeId)
+{
+  mImpl->CancelLoad(id, typeId);
+}
+
+bool ResourceLoader::IsLoading()
+{
+  return mImpl->IsLoading();
+}
+
+void ResourceLoader::SetDpi(unsigned int dpiHor, unsigned int dpiVer)
+{
+  // Unused
+}
+
+bool ResourceLoader::LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const
+{
+  Dali::Vector<unsigned char> daliVec;
+  const bool result = LoadFile( filename, daliVec );
+  buffer.resize( daliVec.Size() );
+  memcpy( &buffer[0], &daliVec[0], daliVec.Size() );
+  return result;
+}
+
+bool ResourceLoader::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  DALI_LOG_TRACE_METHOD(gLoaderFilter);
+
+  DALI_ASSERT_DEBUG( 0 != filename.length());
+
+  bool result;
+
+  std::filebuf buf;
+  buf.open(filename.c_str(), std::ios::in | std::ios::binary);
+  if( buf.is_open() )
+  {
+    std::istream stream(&buf);
+
+    // determine data length
+    stream.seekg(0, std::ios_base::end);
+    unsigned int length = static_cast<unsigned int>( stream.tellg() );
+    stream.seekg(0, std::ios_base::beg);
+
+    // allocate a buffer
+    buffer.Resize(length);
+    // read data into buffer
+    stream.read(reinterpret_cast<char*>(buffer.Begin()), length);
+
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
+
+    result = true;
+  }
+  else
+  {
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
+    result = false;
+  }
+
+  return result;
+}
+
+std::string ResourceLoader::LoadFile(const std::string& filename) const
+{
+  DALI_LOG_TRACE_METHOD(gLoaderFilter);
+
+  DALI_ASSERT_DEBUG( 0 != filename.length());
+
+  std::string contents;
+
+  std::filebuf buf;
+  buf.open(filename.c_str(), std::ios::in);
+  if( buf.is_open() )
+  {
+    std::istream stream(&buf);
+
+    // determine data length
+    stream.seekg(0, std::ios_base::end);
+    unsigned int length = static_cast<unsigned int>( stream.tellg() );
+    stream.seekg(0, std::ios_base::beg);
+
+    // allocate a buffer
+    contents.resize(length);
+    // read data into buffer
+    stream.read(&contents[0], length);
+
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - loaded %d bytes\n", filename.c_str(), length);
+  }
+  else
+  {
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::LoadFile(%s) - failed to load\n", filename.c_str());
+  }
+
+  return contents;
+}
+
+bool ResourceLoader::SaveFile(const std::string& filename, std::vector< unsigned char >& buffer)
+{
+  return SaveFile( filename, &buffer[0], buffer.size() );
+}
+
+bool ResourceLoader::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes )
+{
+  DALI_LOG_TRACE_METHOD(gLoaderFilter);
+
+  DALI_ASSERT_DEBUG( 0 != filename.length());
+
+  bool result = false;
+
+  std::filebuf buf;
+  buf.open(filename.c_str(), std::ios::out | std::ios_base::trunc | std::ios::binary);
+  if( buf.is_open() )
+  {
+    std::ostream stream(&buf);
+
+    // determine size of buffer
+    int length = static_cast<int>(numBytes);
+
+    // write contents of buffer to the file
+    stream.write(reinterpret_cast<const char*>(buffer), length);
+
+    if( !stream.bad() )
+    {
+      DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - wrote %d bytes\n", filename.c_str(), length);
+      result = true;
+    }
+  }
+
+#if defined(DEBUG_BUILD)
+  if( !result )
+  {
+    DALI_LOG_INFO(gLoaderFilter, Debug::Verbose, "ResourceLoader::SaveFile(%s) - failed to load\n", filename.c_str());
+  }
+#endif
+
+  return result;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/resource-loader/resource-loader.h b/platform-abstractions/tizen/resource-loader/resource-loader.h
new file mode 100644 (file)
index 0000000..d493c56
--- /dev/null
@@ -0,0 +1,292 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_LOADER_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_LOADER_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/integration-api/resource-cache.h>
+#include <dali/public-api/common/dali-vector.h>
+
+#include <string>
+
+namespace Dali
+{
+
+namespace Integration
+{
+namespace Log
+{
+class Filter;
+}
+}
+
+namespace TizenPlatform
+{
+
+/**
+ * Contains information about a successfully loaded resource
+ */
+struct LoadedResource
+{
+  /**
+   * Constructor
+   * @param[in] loadedId        The ID of the resource
+   * @param[in] loadedType      The resource type
+   * @param[in] loadedResource  A pointer to the loaded resource data
+   */
+  LoadedResource(Integration::ResourceId      loadedId,
+                 Integration::ResourceTypeId  loadedType,
+                 Integration::ResourcePointer loadedResource)
+  : id(loadedId),
+    type(loadedType),
+    resource(loadedResource)
+  {
+  }
+
+  /// Copy constructor
+  LoadedResource(const LoadedResource& loaded)
+  : id(loaded.id),
+    type(loaded.type),
+    resource(loaded.resource)
+  {
+  }
+
+  /// Assignment operator
+  LoadedResource& operator=(const LoadedResource& rhs)
+  {
+    if( this != &rhs )
+    {
+      id = rhs.id;
+      type = rhs.type;
+      resource = rhs.resource;
+    }
+    return *this;
+  }
+
+  Integration::ResourceId      id;         ///< Integer ID
+  Integration::ResourceTypeId  type;       ///< Type enum (bitmap, ...)
+  Integration::ResourcePointer resource;   ///< Reference counting pointer to the loaded / decoded representation  of the resource.
+};
+
+/**
+ * Contains information about a successfully saved resource
+ */
+struct SavedResource
+{
+  /**
+   * Constructor
+   * @param[in] savedId   The ID of the resource
+   * @param[in] savedType The resource type
+   */
+  SavedResource(Integration::ResourceId     savedId,
+                Integration::ResourceTypeId savedType)
+  : id(savedId),
+    type(savedType)
+  {
+  }
+
+  /// Copy constructor
+  SavedResource(const LoadedResource& loaded)
+  : id(loaded.id),
+    type(loaded.type)
+  {
+  }
+
+  /// Assignment operator
+  SavedResource& operator=(const SavedResource& rhs)
+  {
+    if( this != &rhs )
+    {
+      id = rhs.id;
+      type = rhs.type;
+    }
+    return *this;
+  }
+
+  Integration::ResourceId     id;
+  Integration::ResourceTypeId type;
+};
+
+/**
+ * Contains information about a failed resource load/save request
+ */
+struct FailedResource
+{
+  FailedResource(Integration::ResourceId resourceId, Integration::ResourceFailure failure):
+    id(resourceId),
+    failureType(failure)
+  {
+  }
+
+  /// Copy constructor
+  FailedResource(const FailedResource& failed)
+  : id(failed.id),
+    failureType(failed.failureType)
+  {
+  }
+
+  /// Assignment operator
+  FailedResource& operator=(const FailedResource& rhs)
+  {
+    if( this != &rhs )
+    {
+      id = rhs.id;
+      failureType = rhs.failureType;
+    }
+    return *this;
+  }
+
+  Integration::ResourceId      id;
+  Integration::ResourceFailure failureType;
+};
+
+/**
+ * This implements the resource loading part of the PlatformAbstraction API.
+ * The requests for a specific resource type are farmed-out to a resource
+ * requester for that type which handles them in their own dedicated loading
+ * threads.
+ */
+class ResourceLoader
+{
+public:
+
+  /**
+   * Create a resource loader.
+   * There should exactly one of these objects per Dali Core.
+   */
+  ResourceLoader();
+
+  /**
+   * Non-virtual destructor.
+   * ResourceLoader is NOT intended as a base class.
+   */
+  ~ResourceLoader();
+
+  /**
+   * Pause processing of already-queued resource requests.
+   */
+  void Pause();
+
+  /**
+   * Continue processing resource requests.
+   */
+  void Resume();
+
+  /**
+   * Check if the ResourceLoader is terminating
+   * @return true if terminating else false
+   */
+  bool IsTerminating();
+
+  /**
+   * Add a partially loaded resource to the PartiallyLoadedResource queue
+   * @param[in] resource The resource's information and data
+   */
+  void AddPartiallyLoadedResource(LoadedResource& resource);
+
+  /**
+   * Add a completely loaded resource to the LoadedResource queue
+   * @param[in] resource The resource's information and data
+   */
+  void AddLoadedResource(LoadedResource& resource);
+
+  /**
+   * Add a successfully saved resource to the SavedResource queue
+   * @param[in] resource The resource's information
+   */
+  void AddSavedResource(SavedResource& resource);
+
+  /**
+   * Add information about a failed resource load to the FailedLoads queue
+   * @param[in] resource The failed resource's information
+   */
+  void AddFailedLoad(FailedResource& resource);
+
+  /**
+   * Add information about a failed resource save to the FailedSaves queue
+   * @param[in] resource The failed resource's information
+   */
+  void AddFailedSave(FailedResource& resource);
+
+
+  // From PlatformAbstraction
+
+  /**
+   * @copydoc PlatformAbstraction::LoadResource()
+   */
+  void LoadResource(const Integration::ResourceRequest& request);
+
+  /**
+   * @copydoc PlatformAbstraction::CancelLoad()
+   */
+  void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId);
+
+  /**
+   * @copydoc PlatformAbstraction::IsLoading()
+   * @deprecated This is not implemented: always returns true.
+   */
+  bool IsLoading();
+
+  /**
+   * @copydoc PlatformAbstraction::GetResources()
+   */
+  void GetResources(Integration::ResourceCache& cache);
+
+  /**
+   * @copydoc PlatformAbstraction::SetDpi()
+   */
+  void SetDpi(unsigned int dpiHor, unsigned int dpiVer);
+
+  /**
+   * @copydoc SlpPlatformAbstraction::LoadFile()
+   */
+  bool LoadFile( const std::string& filename, std::vector< unsigned char >& buffer ) const;
+  bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
+
+  /**
+   * @copydoc TizenPlatformAbstraction::LoadFile()
+   */
+  std::string LoadFile(const std::string& filename) const;
+
+  /**
+   * @copydoc TizenPlatformAbstraction::SaveFile()
+   */
+  static bool SaveFile( const std::string& filename, std::vector< unsigned char >& buffer );
+  static bool SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes );
+
+private:
+
+  // Undefined
+  ResourceLoader( const ResourceLoader& resourceLoader );
+
+  // Undefined
+  ResourceLoader& operator=( const ResourceLoader& resourceLoader );
+
+private:
+  struct ResourceLoaderImpl;
+  ResourceLoaderImpl* mImpl;
+
+  volatile int mTerminateThread;        ///< Set to <> 0 in destructor, signals threads to exit their controlling loops
+
+};
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_LOADER_H_
diff --git a/platform-abstractions/tizen/resource-loader/resource-loading-client.h b/platform-abstractions/tizen/resource-loader/resource-loading-client.h
new file mode 100644 (file)
index 0000000..27c07f0
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _DALI_PLATFORM_RESOURCE_LOADING_CLIENT_H_
+#define _DALI_PLATFORM_RESOURCE_LOADING_CLIENT_H_
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+/**
+ * @brief Abstract interface to the caller of a low-level resource loading
+ * function such as a loader for an image format.
+ */
+class ResourceLoadingClient
+{
+public:
+  /**
+   * @brief Check whether the current request has been cancelled.
+   *
+   * This will throw an exception to unwind the stack if the current request
+   * has been cancelled.
+   *
+   * @note Only place calls to this function at exception-safe locations in loader code.
+   **/
+  virtual void InterruptionPoint() const = 0;
+
+protected:
+  /** Construction is restricted to derived / implementing classes. */
+  ResourceLoadingClient() {}
+  /** Destruction of an object through this interface is not allowed. */
+  ~ResourceLoadingClient() {}
+
+private:
+  ResourceLoadingClient( const ResourceLoadingClient& rhs );
+  ResourceLoadingClient& operator =( ResourceLoadingClient& rhs );
+};
+
+/**
+ * @brief Default implementation of a caller of a low-level resource loading
+ * function which does nothing.
+ */
+class StubbedResourceLoadingClient : public ResourceLoadingClient
+{
+public:
+  /**
+   * @brief Check whether the current request has been cancelled.
+   *
+   * This does nothing and so can never throw an exception.
+   **/
+  virtual void InterruptionPoint() const {}
+
+  /** Construction is a NOP. */
+  StubbedResourceLoadingClient() {}
+  /** Destruction has no work to do. */
+  ~StubbedResourceLoadingClient() {}
+
+private:
+  StubbedResourceLoadingClient( const StubbedResourceLoadingClient& rhs );
+  StubbedResourceLoadingClient& operator =( StubbedResourceLoadingClient& rhs );
+};
+
+} /* namespace TizenPlatform */
+} /* namespace Dali */
+
+#endif /* _DALI_PLATFORM_RESOURCE_LOADING_CLIENT_H_ */
diff --git a/platform-abstractions/tizen/resource-loader/resource-requester-base.cpp b/platform-abstractions/tizen/resource-loader/resource-requester-base.cpp
new file mode 100644 (file)
index 0000000..8714d76
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "resource-requester-base.h"
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+ResourceRequesterBase::ResourceRequesterBase( ResourceLoader& resourceLoader )
+: mResourceLoader(resourceLoader)
+{
+}
+
+ResourceRequesterBase::~ResourceRequesterBase()
+{
+}
+
+} // Namespace TizenPlatform
+} // Namespace Dali
diff --git a/platform-abstractions/tizen/resource-loader/resource-requester-base.h b/platform-abstractions/tizen/resource-loader/resource-requester-base.h
new file mode 100644 (file)
index 0000000..71ba1d6
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_REQUESTER_BASE_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_REQUESTER_BASE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <platform-abstractions/tizen/resource-loader/resource-loader.h>
+#include <dali/integration-api/resource-request.h>
+#include <dali/integration-api/resource-cache.h>
+
+namespace Dali
+{
+namespace Integration
+{
+class ResourceRequest;
+}
+
+namespace TizenPlatform
+{
+
+/**
+ * Base class to handle resource requests
+ */
+class ResourceRequesterBase
+{
+public:
+  /**
+   * Constructor
+   * @param[in] resourceLoader The resource loader with which to communicate results
+   */
+  ResourceRequesterBase( ResourceLoader& resourceLoader );
+
+  /**
+   * Destructor
+   */
+  virtual ~ResourceRequesterBase();
+
+  /**
+   * Pause starting new work on background threads, but keep that work queued.
+   */
+  virtual void Pause() = 0;
+
+  /**
+   * Resume processing tasks on background threads.
+   */
+  virtual void Resume() = 0;
+
+  /**
+   * Load a resource.
+   * @param[in] request The resource request
+   */
+  virtual void LoadResource( Integration::ResourceRequest& request ) = 0;
+
+  /**
+   * Load more resources (for partial loading)
+   * @param[in] request The initial load request
+   * @param[in] partialResource The resources loaded by the last request
+   * @return LOADING or PARTIALLY_LOADED if more resources to come, COMPLETELY_LOADED if complete
+   */
+  virtual Integration::LoadStatus LoadFurtherResources( Integration::ResourceRequest& request, LoadedResource partialResource ) = 0;
+
+  /**
+   * Cancal load requests
+   * @param[in] id The request id of the loading request
+   * @param[in] typeId The resource type id of the loading request
+   */
+  virtual void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId) = 0;
+
+protected:
+  ResourceLoader& mResourceLoader; ///< The resource loader to which to send results
+
+private:
+  /**
+   * Undefined default constructor
+   */
+  ResourceRequesterBase();
+
+  /**
+   * Undefined Copy constructor
+   */
+  ResourceRequesterBase(const ResourceRequesterBase& rhs );
+
+  /**
+   * Undefined Assignment operator
+   */
+  ResourceRequesterBase& operator=(const ResourceRequesterBase& rhs );
+};
+
+} // TizenPlatform
+} // Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_REQUESTER_BASE_H__
diff --git a/platform-abstractions/tizen/resource-loader/resource-thread-base.cpp b/platform-abstractions/tizen/resource-loader/resource-thread-base.cpp
new file mode 100644 (file)
index 0000000..e3f101f
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/debug.h>
+#include "resource-thread-base.h"
+#include "tizen-logging.h"
+#include "atomics.h"
+
+using namespace Dali::Integration;
+using boost::mutex;
+using boost::unique_lock;
+
+namespace Dali
+{
+
+// Initial values for the members tracking which resources have been cancelled.
+// They start out with different values so that if the first load executed is
+// synchronous, it won't be erroneously cancelled.
+const Integration::ResourceId NO_REQUEST_IN_FLIGHT = Integration::ResourceId(0) - 1;
+const Integration::ResourceId NO_REQUEST_CANCELLED = Integration::ResourceId(0) - 2;
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const char * const IDLE_PRIORITY_ENVIRONMENT_VARIABLE_NAME = "DALI_RESOURCE_THREAD_IDLE_PRIORITY"; ///@Todo Move this to somewhere that other environment variables are declared and document it there.
+} // unnamed namespace
+
+/** Thrown by InterruptionPoint() to abort a request early. */
+class CancelRequestException {};
+
+ResourceThreadBase::ResourceThreadBase( ResourceLoader& resourceLoader ) :
+  mResourceLoader( resourceLoader ),
+  mCurrentRequestId( NO_REQUEST_IN_FLIGHT ),
+  mCancelRequestId( NO_REQUEST_CANCELLED ),
+  mPaused( false )
+{
+#if defined(DEBUG_ENABLED)
+  mLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_RESOURCE_THREAD_BASE");
+#endif
+
+  mThread = new boost::thread(boost::bind(&ResourceThreadBase::ThreadLoop, this));
+}
+
+ResourceThreadBase::~ResourceThreadBase()
+{
+  TerminateThread();
+
+#if defined(DEBUG_ENABLED)
+  delete mLogFilter;
+#endif
+}
+
+void ResourceThreadBase::TerminateThread()
+{
+  if (mThread)
+  {
+    // wake thread
+    mCondition.notify_all();
+    // wait for thread to exit
+    mThread->join();
+    // delete thread instance
+    delete mThread;
+    // mark thread terminated
+    mThread = NULL;
+  }
+}
+
+void ResourceThreadBase::AddRequest(const ResourceRequest& request, const RequestType type)
+{
+  bool wasEmpty = false;
+  bool wasPaused = false;
+
+  {
+    // Lock while adding to the request queue
+    unique_lock<mutex> lock( mMutex );
+
+    wasEmpty = mQueue.empty();
+    wasPaused = mPaused;
+
+    mQueue.push_back( std::make_pair(request, type) );
+  }
+
+  if( wasEmpty && !wasPaused )
+  {
+    // Wake-up the thread
+    mCondition.notify_all();
+  }
+}
+
+// Called from outer thread.
+void ResourceThreadBase::CancelRequest( const Integration::ResourceId resourceId )
+{
+  bool found = false;
+  DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s: %u.\n", __FUNCTION__, unsigned(resourceId) );
+
+  // Eliminate the cancelled request from the request queue if it is in there:
+  {
+    // Lock while searching and removing from the request queue:
+    unique_lock<mutex> lock( mMutex );
+
+    for( RequestQueueIter iterator = mQueue.begin();
+         iterator != mQueue.end();
+         ++iterator )
+    {
+      if( ((*iterator).first).GetId() == resourceId )
+      {
+        iterator = mQueue.erase( iterator );
+        found = true;
+        break;
+      }
+    }
+  }
+
+  // Remember the cancelled id for the worker thread to poll at one of its points
+  // of interruption:
+  if( !found )
+  {
+    Dali::Internal::AtomicWriteToCacheableAlignedAddress( &mCancelRequestId, resourceId );
+    DALI_LOG_INFO( mLogFilter, Debug::Concise, "%s: Cancelling in-flight resource (%u).\n", __FUNCTION__, unsigned(resourceId) );
+  }
+}
+
+// Called from worker thread.
+void ResourceThreadBase::InterruptionPoint() const
+{
+  const Integration::ResourceId cancelled = Dali::Internal::AtomicReadFromCacheableAlignedAddress( &mCancelRequestId );
+  const Integration::ResourceId current = mCurrentRequestId;
+
+  if( current == cancelled )
+  {
+    DALI_LOG_INFO( mLogFilter, Debug::Concise, "%s: Cancelled in-flight resource (%u).\n", __FUNCTION__, unsigned(cancelled) );
+    throw CancelRequestException();
+  }
+}
+
+void ResourceThreadBase::Pause()
+{
+  unique_lock<mutex> lock( mMutex );
+  mPaused = true;
+}
+
+void ResourceThreadBase::Resume()
+{
+  // Clear the paused flag and if we weren't running already, also wake up the background thread:
+  bool wasPaused = false;
+  {
+    unique_lock<mutex> lock( mMutex );
+    wasPaused = mPaused;
+    mPaused = false;
+  }
+
+  // If we were paused, wake up the background thread and give it a
+  // chance to do some work:
+  if( wasPaused )
+  {
+    mCondition.notify_all();
+  }
+}
+
+//----------------- Called from separate thread (mThread) -----------------
+
+void ResourceThreadBase::ThreadLoop()
+{
+  // TODO: Use Environment Options
+  const char* threadPriorityIdleRequired = std::getenv( IDLE_PRIORITY_ENVIRONMENT_VARIABLE_NAME );
+  if( threadPriorityIdleRequired )
+  {
+    // if the parameter exists then set up an idle priority for this thread
+    struct sched_param sp;
+    sp.sched_priority = 0;
+    sched_setscheduler(0, SCHED_IDLE, &sp);
+    ///@ToDo: change to the corresponding Pthreads call, not this POSIX.1-2001 one with a Linux-specific argument (SCHED_IDLE): int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);, as specified in the docs for sched_setscheduler(): http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
+  }
+
+  InstallLogging();
+
+  while( !mResourceLoader.IsTerminating() )
+  {
+    try
+    {
+      WaitForRequests();
+
+      if ( !mResourceLoader.IsTerminating() )
+      {
+        ProcessNextRequest();
+      }
+    }
+
+    catch( CancelRequestException& ex )
+    {
+      // No problem: a derived class deliberately threw to abort an in-flight request
+      // that was cancelled.
+      DALI_LOG_INFO( mLogFilter, Debug::Concise, "%s: Caught cancellation exception for resource (%u).\n", __FUNCTION__, unsigned(mCurrentRequestId) );
+      CancelRequestException* disableUnusedVarWarning = &ex;
+      ex = *disableUnusedVarWarning;
+    }
+
+    // Catch all exceptions to avoid killing the process, and log the error:
+    catch( std::exception& ex )
+    {
+      const char * const what = ex.what();
+      DALI_LOG_ERROR( "std::exception caught in resource thread. Aborting request with id %u because of std::exception with reason, \"%s\".\n", unsigned(mCurrentRequestId), what ? what : "null" );
+    }
+    catch( Dali::DaliException& ex )
+    {
+      // Probably a failed assert-always:
+      DALI_LOG_ERROR( "DaliException caught in resource thread. Aborting request with id %u. Location: \"%s\". Condition: \"%s\".\n", unsigned(mCurrentRequestId), ex.location, ex.condition );
+    }
+    catch( ... )
+    {
+      DALI_LOG_ERROR( "Unknown exception caught in resource thread. Aborting request with id %u.\n", unsigned(mCurrentRequestId) );
+    }
+  }
+}
+
+void ResourceThreadBase::WaitForRequests()
+{
+  unique_lock<mutex> lock( mMutex );
+
+  if( mQueue.empty() || mPaused == true )
+  {
+    // Waiting for a wake up from resource loader control thread
+    // This will be to process a new request or terminate
+    mCondition.wait(lock);
+  }
+}
+
+void ResourceThreadBase::ProcessNextRequest()
+{
+  ResourceRequest* request(NULL);
+  RequestType type(RequestLoad);
+
+  {
+    // lock the queue and extract the next request
+    unique_lock<mutex> lock(mMutex);
+
+    if (!mQueue.empty())
+    {
+      const RequestInfo & front = mQueue.front();
+      request = new ResourceRequest( front.first );
+      type = front.second;
+      mCurrentRequestId = front.first.GetId();
+      mQueue.pop_front();
+    }
+  } // unlock the queue
+
+  // process request outside of lock
+  if ( NULL != request )
+  {
+    std::auto_ptr<ResourceRequest> deleter( request );
+    switch( type )
+    {
+      case RequestLoad:
+      {
+        Load(*request);
+      }
+      break;
+
+      case RequestDownload:
+      {
+        Download(*request);
+      }
+      break;
+
+      case RequestDecode:
+      {
+        Decode(*request);
+      }
+      break;
+
+      case RequestSave:
+      {
+        Save(*request);
+      }
+      break;
+    }
+  }
+}
+
+void ResourceThreadBase::InstallLogging()
+{
+  // resource loading thread will send its logs to TIZEN Platform's LogMessage handler.
+  Dali::Integration::Log::InstallLogFunction(Dali::TizenPlatform::LogMessage);
+}
+
+void ResourceThreadBase::UninstallLogging()
+{
+  // uninstall it on resource loading thread.
+  Dali::Integration::Log::UninstallLogFunction();
+}
+
+void ResourceThreadBase::Download(const Integration::ResourceRequest& request)
+{
+  DALI_LOG_TRACE_METHOD(mLogFilter);
+  DALI_LOG_WARNING("Resource Downloading from a remote server not supported for this type.");
+  ///! If you need this for a subclassed thread, look to ResourceThreadImage::Download() for an example implementation.
+}
+
+void ResourceThreadBase::Decode(const Integration::ResourceRequest& request)
+{
+  DALI_LOG_TRACE_METHOD(mLogFilter);
+  DALI_LOG_WARNING("Resource Decoding from a memory buffer not supported for this type.");
+  ///! If you need this for a subclassed thread, look to ResourceThreadImage::Decode() for an example implementation.
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/resource-loader/resource-thread-base.h b/platform-abstractions/tizen/resource-loader/resource-thread-base.h
new file mode 100644 (file)
index 0000000..9a88a67
--- /dev/null
@@ -0,0 +1,186 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_BASE_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_BASE_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include "resource-loader.h"
+#include "resource-loading-client.h"
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/integration-api/resource-cache.h>
+
+// EXTERNAL INCLUDES
+#include <deque>
+#include <boost/thread.hpp>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+/**
+ * Resource loader worker thread
+ */
+class ResourceThreadBase : public ResourceLoadingClient
+{
+public:
+  // typedefs and enums
+
+  /** Client threads send work to resource threads through Requests, for which
+   *  this type identifies the action to be taken on the resource thread. */
+  enum RequestType
+  {
+    /** Pull a resource out of the platform's file system. */
+    RequestLoad,
+    /** Pull a resource from the network. */
+    RequestDownload,
+    /** Pull a resource out of a memory buffer. */
+    RequestDecode,
+    /** Push a resource's data out to the file system. */
+    RequestSave
+  };
+
+  typedef std::pair<Integration::ResourceRequest, RequestType>  RequestInfo;
+  typedef std::deque<RequestInfo>                               RequestQueue;
+  typedef RequestQueue::iterator                                RequestQueueIter;
+
+public:
+  // Constructor
+  ResourceThreadBase(ResourceLoader& resourceLoader);
+
+  // Destructor
+  virtual ~ResourceThreadBase();
+
+protected:
+  void TerminateThread();
+
+public:
+  /**
+   * Add a resource request to the back of the queue
+   * @param[in] request The requested resource/file url and attributes
+   * @param[in] type    Load or save flag
+   */
+  void AddRequest(const Integration::ResourceRequest& request, const RequestType type);
+
+  /**
+   * Cancel a resource request. Removes the request from the queue.
+   * @param[in] resourceId ID of the resource to be canceled
+   */
+  void CancelRequest(Integration::ResourceId  resourceId);
+
+  /**
+   * Pause starting new work in the background, but keep that work queued.
+   */
+  void Pause();
+
+  /**
+   * Resume processing tasks on background thread.
+   */
+  void Resume();
+
+
+protected:
+  /**
+   * Main control loop for the thread.
+   * The thread is terminated when this function exits
+   */
+  void ThreadLoop();
+
+  /**
+   * Wait for an incoming resource request or termination
+   */
+  void WaitForRequests();
+
+  /**
+   * Process the resource request at the head of the queue
+   */
+  void ProcessNextRequest();
+
+  /**
+   * Install a logging function in to core for this thread.
+   */
+  void InstallLogging();
+
+  /**
+   * Uninstall a logging function.
+   */
+  void UninstallLogging();
+
+  /**
+   * Load a resource
+   * @param[in] request  The requested resource/file url and attributes
+   */
+  virtual void Load(const Integration::ResourceRequest& request) = 0;
+
+  /**
+   * Download a resource
+   * @param[in] request  The requested resource/file url and attributes
+   */
+  virtual void Download(const Integration::ResourceRequest& request);
+
+  /**
+   * Decode a resource exactly as if it were being loaded but source its data
+   * from a memory buffer attached directly to the request object.
+   * @param[in] request  The requested resource data and attributes
+   */
+  virtual void Decode(const Integration::ResourceRequest& request);
+
+  /**
+   * Save a resource
+   * @param[in] request  The requested resource/file url and attributes
+   */
+  virtual void Save(const Integration::ResourceRequest& request) = 0;
+
+  /**
+   * @brief Cancels current resource request if it matches the one latched to be cancelled.
+   *
+   * @copydoc ResourceLoadingClient::InterruptionPoint
+   */
+  virtual void InterruptionPoint() const;
+
+protected:
+  ResourceLoader& mResourceLoader;
+  boost::thread* mThread;                       ///< thread instance
+  boost::condition_variable mCondition;         ///< condition variable
+  boost::mutex mMutex;                          ///< used to protect mQueue
+  RequestQueue mQueue;                          ///< Request queue
+private:
+  Integration::ResourceId mCurrentRequestId;    ///< Current request, set by worker thread
+  volatile Integration::ResourceId mCancelRequestId; ///< Request to be cancelled on thread: written by external thread and read by worker.
+  bool mPaused;                                ///< Whether to process work in mQueue
+
+private:
+
+  // Undefined
+  ResourceThreadBase( const ResourceThreadBase& resourceThreadBase );
+
+  // Undefined
+  ResourceThreadBase& operator=( const ResourceThreadBase& resourceThreadBase );
+
+#if defined(DEBUG_ENABLED)
+public:
+  Integration::Log::Filter* mLogFilter;
+#endif
+}; // class ResourceThreadBase
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_BASE_H__
diff --git a/platform-abstractions/tizen/resource-loader/resource-thread-image.cpp b/platform-abstractions/tizen/resource-loader/resource-thread-image.cpp
new file mode 100755 (executable)
index 0000000..5838721
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "resource-thread-image.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/ref-counted-dali-vector.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/resource-cache.h>
+#include <dali/integration-api/resource-types.h>
+
+// INTERNAL INCLUDES
+#include "portable/file-closer.h"
+#include "image-loaders/image-loader.h"
+#include "network/file-download.h"
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+// limit maximum image down load size to 50 MB
+const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024 ;
+}
+
+ResourceThreadImage::ResourceThreadImage(ResourceLoader& resourceLoader)
+: ResourceThreadBase(resourceLoader)
+{
+}
+
+ResourceThreadImage::~ResourceThreadImage()
+{
+}
+
+void ResourceThreadImage::Load(const ResourceRequest& request)
+{
+  DALI_LOG_TRACE_METHOD( mLogFilter );
+  DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
+
+  LoadImageFromLocalFile(request);
+}
+
+void ResourceThreadImage::Download(const ResourceRequest& request)
+{
+  bool succeeded;
+
+  DALI_LOG_TRACE_METHOD( mLogFilter );
+  DALI_LOG_INFO( mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str() );
+
+  Dali::Vector<uint8_t> dataBuffer;
+  size_t dataSize;
+  succeeded = DownloadRemoteImageIntoMemory( request, dataBuffer, dataSize );
+  if( succeeded )
+  {
+    DecodeImageFromMemory(static_cast<void*>(&dataBuffer[0]), dataBuffer.Size(), request);
+  }
+}
+
+void ResourceThreadImage::Decode(const ResourceRequest& request)
+{
+  DALI_LOG_TRACE_METHOD( mLogFilter );
+  DALI_LOG_INFO(mLogFilter, Debug::Verbose, "%s(%s)\n", __FUNCTION__, request.GetPath().c_str());
+
+  // Get the blob of binary data that we need to decode:
+  DALI_ASSERT_DEBUG( request.GetResource() );
+
+  DALI_ASSERT_DEBUG( 0 != dynamic_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() ) && "Only blobs of binary data can be decoded." );
+  Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( request.GetResource().Get() );
+
+  if( 0 != encodedBlob )
+  {
+    const size_t blobSize     = encodedBlob->GetVector().Size();
+    uint8_t * const blobBytes = &(encodedBlob->GetVector()[0]);
+    DecodeImageFromMemory(blobBytes, blobSize, request);
+  }
+  else
+  {
+    FailedResource resource(request.GetId(), FailureUnknown);
+    mResourceLoader.AddFailedLoad(resource);
+  }
+}
+
+void ResourceThreadImage::Save(const Integration::ResourceRequest& request)
+{
+  DALI_LOG_TRACE_METHOD( mLogFilter );
+  DALI_ASSERT_DEBUG( request.GetType()->id == ResourceBitmap );
+  DALI_LOG_WARNING( "Image saving not supported on background resource threads." );
+}
+
+bool ResourceThreadImage::DownloadRemoteImageIntoMemory(const Integration::ResourceRequest& request, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize)
+{
+  bool ok = Network::DownloadRemoteFileIntoMemory( request.GetPath(), dataBuffer,  dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+  if( !ok )
+  {
+    FailedResource resource(request.GetId(), FailureUnknown);
+    mResourceLoader.AddFailedLoad(resource);
+  }
+  return ok;
+}
+
+void ResourceThreadImage::LoadImageFromLocalFile(const Integration::ResourceRequest& request)
+{
+  bool fileNotFound = false;
+  BitmapPtr bitmap = 0;
+  bool result = false;
+
+  Dali::Internal::Platform::FileCloser fileCloser( request.GetPath().c_str(), "rb" );
+  FILE * const fp = fileCloser.GetFile();
+
+  if( NULL != fp )
+  {
+    result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, *this, bitmap );
+    // Last chance to interrupt a cancelled load before it is reported back to clients
+    // which have already stopped tracking it:
+    InterruptionPoint(); // Note: This can throw an exception.
+    if( result && bitmap )
+    {
+      // Construct LoadedResource and ResourcePointer for image data
+      LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
+      // Queue the loaded resource
+      mResourceLoader.AddLoadedResource( resource );
+    }
+    else
+    {
+      DALI_LOG_WARNING( "Unable to decode %s\n", request.GetPath().c_str() );
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING( "Failed to open file to load \"%s\"\n", request.GetPath().c_str() );
+    fileNotFound = true;
+  }
+
+  if ( !bitmap )
+  {
+    if( fileNotFound )
+    {
+      FailedResource resource(request.GetId(), FailureFileNotFound  );
+      mResourceLoader.AddFailedLoad(resource);
+    }
+    else
+    {
+      FailedResource resource(request.GetId(), FailureUnknown);
+      mResourceLoader.AddFailedLoad(resource);
+    }
+  }
+}
+
+void ResourceThreadImage::DecodeImageFromMemory(void* blobBytes, size_t blobSize, const Integration::ResourceRequest& request)
+{
+  BitmapPtr bitmap = 0;
+
+  DALI_ASSERT_DEBUG( blobSize > 0U );
+  DALI_ASSERT_DEBUG( blobBytes != 0U );
+
+  if( blobBytes != 0 && blobSize > 0U )
+  {
+    // Open a file handle on the memory buffer:
+    Dali::Internal::Platform::FileCloser fileCloser( blobBytes, blobSize, "rb" );
+    FILE * const fp = fileCloser.GetFile();
+    if ( NULL != fp )
+    {
+      bool result = ImageLoader::ConvertStreamToBitmap( *request.GetType(), request.GetPath(), fp, StubbedResourceLoadingClient(), bitmap );
+      if ( result && bitmap )
+      {
+        // Construct LoadedResource and ResourcePointer for image data
+        LoadedResource resource( request.GetId(), request.GetType()->id, ResourcePointer( bitmap.Get() ) );
+        // Queue the loaded resource
+        mResourceLoader.AddLoadedResource( resource );
+      }
+      else
+      {
+        DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
+      }
+    }
+  }
+
+  if (!bitmap)
+  {
+    FailedResource resource(request.GetId(), FailureUnknown);
+    mResourceLoader.AddFailedLoad(resource);
+  }
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/resource-loader/resource-thread-image.h b/platform-abstractions/tizen/resource-loader/resource-thread-image.h
new file mode 100644 (file)
index 0000000..91d5188
--- /dev/null
@@ -0,0 +1,96 @@
+#ifndef __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
+#define __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// EXTERNAL INCLUDES
+#include <dali/integration-api/resource-cache.h>
+#include <dali/integration-api/resource-types.h>
+
+// INTERNAL INCLUDES
+#include "resource-thread-base.h"
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+class ResourceThreadImage : public ResourceThreadBase
+{
+public:
+  /**
+   * Constructor
+   * @param[in] resourceLoader A reference to the ResourceLoader
+   */
+  ResourceThreadImage( ResourceLoader& resourceLoader );
+
+  /**
+   * Destructor
+   */
+  virtual ~ResourceThreadImage();
+
+
+private:
+  /**
+   * @copydoc ResourceThreadBase::Load
+   */
+  virtual void Load(const Integration::ResourceRequest& request);
+
+  /**
+   * @copydoc ResourceThreadBase::Download
+   */
+  virtual void Download(const Integration::ResourceRequest& request);
+
+  /**
+   * @copydoc ResourceThreadBase::Decode
+   */
+  virtual void Decode(const Integration::ResourceRequest& request);
+
+  /**
+   *@copydoc ResourceThreadBase::Save
+   */
+  virtual void Save(const Integration::ResourceRequest& request);
+
+  /**
+   * Download a requested image into a memory buffer.
+   * @param[in] request  The requested resource/file url and attributes
+   * @param[out] dataBuffer  A memory buffer object to be written with downloaded image data.
+   * @param[out] dataSize  The size of the memory buffer.
+   */
+  bool DownloadRemoteImageIntoMemory(const Integration::ResourceRequest& request, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize);
+
+  /**
+   * Load a requested image from a local file.
+   * @param[in] request  The requested resource/file url and attributes
+   */
+  void LoadImageFromLocalFile(const Integration::ResourceRequest& request);
+
+  /**
+   * Decode a requested image from a memory buffer.
+   * @param[in] blobBytes  A pointer to the memory buffer containig the requested image data.
+   * @param[in] blobSize  The size of the memory buffer containing the requested image data.
+   * @param[in] request  The requested resource/file url and attributes
+   */
+  void DecodeImageFromMemory(void* blobBytes, size_t blobSize, const Integration::ResourceRequest& request);
+}; // class ResourceThreadImage
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H__
diff --git a/platform-abstractions/tizen/tizen-logging.cpp b/platform-abstractions/tizen/tizen-logging.cpp
new file mode 100644 (file)
index 0000000..af14633
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FUNCTION HEADER
+#include "tizen-logging.h"
+
+// EXTERNAL INCLUDES
+#ifndef DALI_PROFILE_UBUNTU
+#include <dlog.h>
+#else // DALI_PROFILE_UBUNTU
+#include <cstdio>
+#endif
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  const char* DALI_TAG = "DALI";
+
+#ifndef DALI_PROFILE_UBUNTU
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      LOG(LOG_INFO, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      LOG(LOG_WARN, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugError:
+      LOG(LOG_ERROR, DALI_TAG, "%s", message.c_str());
+      break;
+    default:
+      LOG(LOG_DEFAULT, DALI_TAG, "%s", message.c_str());
+      break;
+  }
+#else // DALI_PROFILE_UBUNTU
+  const char *format = NULL;
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      format = "\e[1;34mINFO:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      format = "\e[1;33mWARN:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugError:
+      format = "\e[1;91mERROR:\e[21m %s: %s\e[0m";
+      break;
+    default:
+      format = ":\e[21m %s: %s\e[0m";
+      break;
+  }
+  printf(format, DALI_TAG, message.c_str());
+#endif // DALI_PROFILE_UBUNTU
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/platform-abstractions/tizen/tizen-logging.h b/platform-abstractions/tizen/tizen-logging.h
new file mode 100644 (file)
index 0000000..6165227
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __DALI_TIZEN_LOGGING_H__
+#define __DALI_TIZEN_LOGGING_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/debug.h>
+
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+/**
+ * @copydoc Dali::Integration::Log:LogMessage
+ */
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message);
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // __DALI_TIZEN_LOGGING_H__
diff --git a/platform-abstractions/tizen/tizen-platform-abstraction.cpp b/platform-abstractions/tizen/tizen-platform-abstraction.cpp
new file mode 100644 (file)
index 0000000..ebc9fad
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "tizen-platform-abstraction.h"
+
+#ifndef DALI_PROFILE_UBUNTU
+#include <vconf.h>
+#endif // DALI_PROFILE_UBUNTU
+#include <dirent.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/resource-types.h>
+
+// INTERNAL INCLUDES
+#include "resource-loader/resource-loader.h"
+#include "image-loaders/image-loader.h"
+#include "portable/file-closer.h"
+
+namespace Dali
+{
+
+Integration::PlatformAbstraction* CreatePlatformAbstraction()
+{
+  return new TizenPlatform::TizenPlatformAbstraction();
+}
+
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int NANOSECS_TO_MICROSECS( 1000 );               ///< 1000 nanoseconds = 1 microsecond
+}
+
+TizenPlatformAbstraction::TizenPlatformAbstraction()
+: mResourceLoader(new ResourceLoader),
+  mDataStoragePath( "" )
+{
+}
+
+TizenPlatformAbstraction::~TizenPlatformAbstraction()
+{
+  delete mResourceLoader;
+}
+
+void TizenPlatformAbstraction::GetTimeMicroseconds(unsigned int &seconds, unsigned int &microSeconds)
+{
+  timespec time;
+  clock_gettime(CLOCK_MONOTONIC, &time);
+  seconds = time.tv_sec;
+  microSeconds = time.tv_nsec / NANOSECS_TO_MICROSECS;
+}
+
+void TizenPlatformAbstraction::Suspend()
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->Pause();
+  }
+}
+
+void TizenPlatformAbstraction::Resume()
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->Resume();
+  }
+}
+
+int TizenPlatformAbstraction::GetDefaultFontSize() const
+{
+  int fontSize( -1 );
+
+#ifndef DALI_PROFILE_UBUNTU
+  vconf_get_int( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, &fontSize );
+#endif // DALI_PROFILE_UBUNTU
+
+  return fontSize;
+}
+
+ImageDimensions TizenPlatformAbstraction::GetClosestImageSize( const std::string& filename,
+                                                               ImageDimensions size,
+                                                               FittingMode::Type fittingMode,
+                                                               SamplingMode::Type samplingMode,
+                                                               bool orientationCorrection )
+{
+  return ImageLoader::GetClosestImageSize( filename, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+ImageDimensions TizenPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                                               ImageDimensions size,
+                                                               FittingMode::Type fittingMode,
+                                                               SamplingMode::Type samplingMode,
+                                                               bool orientationCorrection )
+{
+  return ImageLoader::GetClosestImageSize( resourceBuffer, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+void TizenPlatformAbstraction::LoadResource(const Integration::ResourceRequest& request)
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->LoadResource(request);
+  }
+}
+
+Integration::ResourcePointer TizenPlatformAbstraction::LoadResourceSynchronously(const Integration::ResourceType& resourceType, const std::string& resourcePath)
+{
+  return ImageLoader::LoadResourceSynchronously( resourceType, resourcePath );
+}
+
+Integration::BitmapPtr TizenPlatformAbstraction::DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t size )
+{
+  Integration::BitmapPtr bitmap = 0;
+
+  Dali::Internal::Platform::FileCloser fileCloser( buffer, size, "rb" );
+  FILE * const fp = fileCloser.GetFile();
+  if( fp )
+  {
+    bool result = ImageLoader::ConvertStreamToBitmap( resourceType, "", fp, StubbedResourceLoadingClient(), bitmap );
+    if ( !result || !bitmap )
+    {
+      bitmap.Reset();
+      DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
+    }
+  }
+
+  return bitmap;
+}
+
+void TizenPlatformAbstraction::CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId)
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->CancelLoad(id, typeId);
+  }
+}
+
+bool TizenPlatformAbstraction::IsLoading()
+{
+  if (mResourceLoader)
+  {
+    return mResourceLoader->IsLoading();
+  }
+
+  return false;
+}
+
+void TizenPlatformAbstraction::GetResources(Integration::ResourceCache& cache)
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->GetResources(cache);
+  }
+}
+
+void TizenPlatformAbstraction::SetDpi(unsigned int dpiHor, unsigned int dpiVer)
+{
+  if (mResourceLoader)
+  {
+    mResourceLoader->SetDpi(dpiHor, dpiVer);
+  }
+}
+
+bool TizenPlatformAbstraction::LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  bool result = false;
+
+  if( mResourceLoader )
+  {
+    result = mResourceLoader->LoadFile( filename, buffer );
+  }
+
+  return result;
+}
+
+std::string TizenPlatformAbstraction::LoadFile( const std::string& filename )
+{
+  std::string result;
+  if (mResourceLoader)
+  {
+    result = mResourceLoader->LoadFile(filename);
+  }
+
+  return result;
+}
+
+bool TizenPlatformAbstraction::SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
+{
+  bool result = false;
+
+  if( mResourceLoader )
+  {
+    result = mResourceLoader->SaveFile( filename, buffer, numBytes );
+  }
+
+  return result;
+}
+
+void TizenPlatformAbstraction::JoinLoaderThreads()
+{
+  delete mResourceLoader;
+  mResourceLoader = NULL;
+}
+
+bool TizenPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  bool result = false;
+
+#ifdef SHADERBIN_CACHE_ENABLED
+  std::string path;
+
+  // First check the system location where shaders are stored at install time:
+  if( mResourceLoader )
+  {
+    path = DALI_SHADERBIN_DIR;
+    path += filename;
+    result = mResourceLoader->LoadFile( path, buffer );
+  }
+
+  // Fallback to the cache of shaders stored after previous runtime compilations:
+  // On desktop this looks in the current working directory that the app was launched from.
+  if( mResourceLoader && result == false )
+  {
+    path = mDataStoragePath;
+    path += filename;
+    result = mResourceLoader->LoadFile( path, buffer );
+  }
+#endif
+
+  return result;
+}
+
+bool TizenPlatformAbstraction::SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
+{
+  bool result = false;
+
+#ifdef SHADERBIN_CACHE_ENABLED
+
+    // Fallback to the cache of shaders stored after previous runtime compilations:
+    // On desktop this looks in the current working directory that the app was launched from.
+    if( mResourceLoader )
+    {
+      std::string path = mDataStoragePath;
+      path += filename;
+      result = mResourceLoader->SaveFile( path, buffer, numBytes );
+    }
+#endif
+
+  return result;
+}
+
+void TizenPlatformAbstraction::SetDataStoragePath( const std::string& path )
+{
+  mDataStoragePath = path;
+}
+
+}  // namespace TizenPlatform
+
+}  // namespace Dali
diff --git a/platform-abstractions/tizen/tizen-platform-abstraction.h b/platform-abstractions/tizen/tizen-platform-abstraction.h
new file mode 100644 (file)
index 0000000..58d6c1d
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef __DALI_TIZEN_PLATFORM_ABSTRACTION_H__
+#define __DALI_TIZEN_PLATFORM_ABSTRACTION_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/integration-api/resource-cache.h>
+#include <dali/public-api/common/dali-common.h>
+
+#include <string>
+
+namespace Dali
+{
+
+/**
+ * Construct a platform abstraction and return it.
+ */
+Integration::PlatformAbstraction* CreatePlatformAbstraction();
+
+namespace TizenPlatform
+{
+
+class ResourceLoader;
+
+/**
+ * Concrete implementation of the platform abstraction class.
+ */
+class TizenPlatformAbstraction : public Integration::PlatformAbstraction
+{
+
+public: // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  TizenPlatformAbstraction();
+
+  /**
+   * Destructor
+   */
+  virtual ~TizenPlatformAbstraction();
+
+public: // PlatformAbstraction overrides
+
+  /**
+   * @copydoc PlatformAbstraction::GetTimeMicroseconds()
+   */
+  virtual void GetTimeMicroseconds(unsigned int &seconds, unsigned int &microSeconds);
+
+  /**
+   * @copydoc PlatformAbstraction::Suspend()
+   */
+  virtual void Suspend();
+
+  /**
+   * @copydoc PlatformAbstraction::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( const std::string& filename,
+                                               ImageDimensions size,
+                                               FittingMode::Type fittingMode,
+                                               SamplingMode::Type samplingMode,
+                                               bool orientationCorrection );
+
+  /**
+   * @copydoc PlatformAbstraction::GetClosestImageSize()
+   */
+  virtual ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                               ImageDimensions size,
+                                               FittingMode::Type fittingMode,
+                                               SamplingMode::Type samplingMode,
+                                               bool orientationCorrection );
+
+  /**
+   * @copydoc PlatformAbstraction::LoadResource()
+   */
+  virtual void LoadResource(const Integration::ResourceRequest& request);
+
+  /**
+   * @copydoc PlatformAbstraction::LoadResourceSynchronously()
+   */
+  virtual Integration::ResourcePointer LoadResourceSynchronously(const Integration::ResourceType& resourceType, const std::string& resourcePath);
+
+  /**
+   * @copydoc PlatformAbstraction::DecodeBuffer()
+   */
+  virtual Integration::BitmapPtr DecodeBuffer( const Integration::ResourceType& resourceType, uint8_t * buffer, size_t size );
+
+  /**
+   * @copydoc PlatformAbstraction::CancelLoad()
+   */
+  virtual void CancelLoad(Integration::ResourceId id, Integration::ResourceTypeId typeId);
+
+  /**
+   * @copydoc PlatformAbstraction::GetResources()
+   */
+  virtual void GetResources(Integration::ResourceCache& cache);
+
+  /**
+   * @copydoc PlatformAbstraction::IsLoading()
+   */
+  virtual bool IsLoading();
+
+  /**
+   * @copydoc PlatformAbstraction::JoinLoaderThreads()
+   */
+  virtual void JoinLoaderThreads();
+
+  /**
+   * @copydoc PlatformAbstraction::GetDefaultFontSize()
+   */
+  virtual int GetDefaultFontSize() const;
+
+  /**
+   * @copydoc PlatformAbstraction::SetDpi()
+   */
+  virtual void SetDpi (unsigned int DpiHorizontal, unsigned int DpiVertical);
+
+  /**
+   * @copydoc PlatformAbstraction::LoadFile()
+   */
+  virtual bool LoadFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
+
+  /**
+   * @copydoc PlatformAbstraction::LoadFile()
+   */
+  virtual std::string LoadFile( const std::string& filename );
+
+  /**
+   * @copydoc PlatformAbstraction::SaveFile()
+   */
+  virtual bool SaveFile(const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const;
+
+  /**
+   * @copydoc PlatformAbstraction::LoadShaderBinaryFile()
+   */
+  virtual bool LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const;
+
+  /**
+   * @copydoc PlatformAbstraction::SaveShaderBinaryFile()
+   */
+  virtual bool SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const;
+
+  /**
+   * Sets path for data/resource storage.
+   * @param[in] path data/resource storage path
+   */
+  void SetDataStoragePath( const std::string& path );
+
+private:
+  ResourceLoader* mResourceLoader;
+  std::string mDataStoragePath;
+};
+
+}  // namespace TizenPlatform
+}  // namespace Dali
+
+#endif // __DALI_TIZEN_PLATFORM_ABSTRACTION_H__
diff --git a/plugins/dali-feedback.cpp b/plugins/dali-feedback.cpp
new file mode 100644 (file)
index 0000000..1be8589
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define LOG_TAG "DALI_FEEDBACK"
+
+// CLASS HEADER
+#include "dali-feedback.h"
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <fstream>
+#include <feedback.h>
+#include <mm_sound.h>
+#include <mm_sound_private.h>
+
+#include <dlog.h>
+
+#define DEBUG_PRINTF(fmt, arg...)  LOGD(" "fmt, ##arg)
+
+using std::string;
+using namespace Dali;
+
+// The plugin factories
+extern "C" DALI_EXPORT_API Dali::FeedbackPlugin* CreateFeedbackPlugin(void)
+{
+  return new Dali::Plugin::DaliFeedback;
+}
+
+namespace Dali
+{
+
+namespace Plugin
+{
+
+DaliFeedback::DaliFeedback()
+: mHapticInitialized( false )
+{
+  feedback_initialize();
+
+  if( 0 == haptic_open( HAPTIC_DEVICE_0, &mDeviceHandle ) )
+  {
+    mHapticInitialized = true;
+  }
+  else
+  {
+    DEBUG_PRINTF( "Haptic feedback controller failed to initialize\n" );
+  }
+}
+
+DaliFeedback::~DaliFeedback()
+{
+  if( mHapticInitialized )
+  {
+    int errorCode = haptic_close( mDeviceHandle );
+    if( errorCode < 0 )
+    {
+      DEBUG_PRINTF( "device_haptic_close() failed with error code: %d\n", errorCode );
+    }
+  }
+
+  feedback_deinitialize();
+}
+
+void DaliFeedback::PlayHaptic( const std::string& filePath )
+{
+  if( mHapticInitialized )
+  {
+    if ( filePath.size() == 0 )
+    {
+      DEBUG_PRINTF( "File Path can't be NULL!\n" );
+      return;
+    }
+
+    int errorCode = haptic_vibrate_file_with_detail( mDeviceHandle, filePath.c_str(), HAPTIC_ITERATION_ONCE, HAPTIC_FEEDBACK_AUTO, HAPTIC_PRIORITY_MIN, NULL );
+    if( errorCode != 0 )
+    {
+      DEBUG_PRINTF( "PlayHaptic() failed with error code: %d\n", errorCode );
+    }
+  }
+  else
+  {
+    DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
+  }
+}
+
+void DaliFeedback::PlayHapticMonotone( unsigned int duration )
+{
+  if( mHapticInitialized )
+  {
+    int errorCode = haptic_vibrate_monotone_with_detail( mDeviceHandle, duration, HAPTIC_FEEDBACK_AUTO, HAPTIC_PRIORITY_MIN, NULL );
+    if( errorCode != 0 )
+    {
+      DEBUG_PRINTF( "PlayHapticMonotone() failed with error code: %d\n", errorCode );
+    }
+  }
+  else
+  {
+    DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
+  }
+}
+
+void DaliFeedback::StopHaptic()
+{
+  if( mHapticInitialized )
+  {
+    int errorCode = haptic_stop_all_effects( mDeviceHandle );
+    if( errorCode != 0 )
+    {
+      DEBUG_PRINTF( "StopHaptic() failed with error code: %d\n", errorCode );
+    }
+  }
+  else
+  {
+    DEBUG_PRINTF( "HapticPlayer is not Initialized\n" );
+  }
+}
+
+int DaliFeedback::PlaySound( const std::string& fileName )
+{
+  int handle = -1;
+  int errorCode = mm_sound_play_keysound( fileName.c_str(), VOLUME_TYPE_SYSTEM & VOLUME_GAIN_TOUCH );
+  if( errorCode < 0 )
+  {
+    DEBUG_PRINTF( "PlaySound() %s failed with error code = %d\n", fileName.c_str(), errorCode );
+  }
+
+  return handle;
+}
+
+void DaliFeedback::StopSound( int handle )
+{
+  int errorCode = mm_sound_stop_sound( handle );
+  if( errorCode < 0 )
+  {
+    DEBUG_PRINTF( "StopSound() handle = %d failed with error code = %d\n", handle, errorCode);
+  }
+  else
+  {
+    DEBUG_PRINTF( "stop handle %d success\n", handle );
+  }
+}
+
+void DaliFeedback::PlayFeedbackPattern( int type, int pattern )
+{
+  int errorCode = feedback_play_type( static_cast<feedback_type_e>(type), static_cast<feedback_pattern_e>(pattern) );
+  if( errorCode != 0 )
+  {
+    DEBUG_PRINTF( "DaliFeedback::PlayFeedbackPattern() with type = %d, pattern = %d returned with error = %d\n", (int)type, (int)pattern, errorCode );
+  }
+}
+
+} // namespace Plugin
+
+} // namespace Dali
+
diff --git a/plugins/dali-feedback.h b/plugins/dali-feedback.h
new file mode 100644 (file)
index 0000000..c9967ec
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef __FEEDBACK_PLUGIN_H__
+#define __FEEDBACK_PLUGIN_H__
+
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#if defined(DALI_PROFILE_MOBILE)
+#include <dd-haptic.h>
+#else
+#include <haptic.h>
+#endif
+
+// INTERNAL INCLUDES
+#include <feedback-plugin.h>
+
+namespace Dali
+{
+
+namespace Plugin
+{
+
+/**
+ * Plays feedback effects for Dali-Toolkit UI Controls.
+ */
+class DaliFeedback : public Dali::FeedbackPlugin
+{
+
+public: // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  DaliFeedback();
+
+  /**
+   * Destructor
+   */
+  virtual ~DaliFeedback();
+
+public: // FeedbackPlugin overrides
+
+  /**
+   * @copydoc Dali::Integration::FeedbackPlugin::PlayHaptic()
+   */
+  void PlayHaptic( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayHapticMonotone()
+   */
+  void PlayHapticMonotone( unsigned int duration );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopHaptic()
+   */
+  void StopHaptic();
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+private:
+
+  haptic_device_h mDeviceHandle;
+
+  bool mHapticInitialized;
+};
+
+}  // namespace Plugin
+
+}  // namespace Dali
+
+#endif // __FEEDBACK_PLUGIN_H__
diff --git a/plugins/file.list b/plugins/file.list
new file mode 100644 (file)
index 0000000..e467ead
--- /dev/null
@@ -0,0 +1,5 @@
+# Add local source files here
+
+plugin_src_files = \
+   $(plugin_src_dir)/dali-feedback.cpp
+
diff --git a/plugins/sounds/file.list b/plugins/sounds/file.list
new file mode 100644 (file)
index 0000000..734874f
--- /dev/null
@@ -0,0 +1,4 @@
+# Files to install here
+
+dali_plugin_sound_files =\
+    $(plugin_sounds_dir)/*.wav
\ No newline at end of file
diff --git a/plugins/sounds/touch.wav b/plugins/sounds/touch.wav
new file mode 100644 (file)
index 0000000..ef6e6ae
Binary files /dev/null and b/plugins/sounds/touch.wav differ
diff --git a/text/dali/devel-api/text-abstraction/bidirectional-support.cpp b/text/dali/devel-api/text-abstraction/bidirectional-support.cpp
new file mode 100644 (file)
index 0000000..8182e9f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text-abstraction/bidirectional-support-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+BidirectionalSupport::BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::~BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::BidirectionalSupport( Internal::BidirectionalSupport* implementation )
+: BaseHandle( implementation )
+{
+}
+
+BidirectionalSupport BidirectionalSupport::Get()
+{
+  return Internal::BidirectionalSupport::Get();
+}
+
+BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
+                                                Length numberOfCharacters )
+{
+  return GetImplementation( *this ).CreateInfo( paragraph,
+                                                numberOfCharacters );
+}
+
+void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
+{
+  GetImplementation( *this ).DestroyInfo( bidiInfoIndex );
+}
+
+void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
+                                    CharacterIndex firstCharacterIndex,
+                                    Length numberOfCharacters,
+                                    CharacterIndex* visualToLogicalMap )
+{
+  GetImplementation( *this ).Reorder( bidiInfoIndex,
+                                      firstCharacterIndex,
+                                      numberOfCharacters,
+                                      visualToLogicalMap );
+}
+
+bool BidirectionalSupport::GetMirroredText( Character* text,
+                                            Length numberOfCharacters )
+{
+  return GetImplementation( *this ).GetMirroredText( text,
+                                                     numberOfCharacters );
+}
+
+bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+{
+  return GetImplementation( *this ).GetParagraphDirection( bidiInfoIndex );
+}
+
+void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                                                   CharacterDirection* directions,
+                                                   Length numberOfCharacters )
+{
+  GetImplementation( *this ).GetCharactersDirection( bidiInfoIndex,
+                                                     directions,
+                                                     numberOfCharacters );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/bidirectional-support.h b/text/dali/devel-api/text-abstraction/bidirectional-support.h
new file mode 100644 (file)
index 0000000..255a94a
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef __DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H__
+#define __DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class BidirectionalSupport;
+
+} // Internal
+
+/**
+ * BidirectionalSupport API
+ *
+ */
+class DALI_IMPORT_API BidirectionalSupport : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   *
+   */
+  BidirectionalSupport();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~BidirectionalSupport();
+
+  /**
+   * @brief This constructor is used by BidirectionalSupport::Get().
+   *
+   * @param[in] implementation a pointer to the internal bidirectional support object.
+   */
+  explicit DALI_INTERNAL BidirectionalSupport( Internal::BidirectionalSupport* implementation );
+
+  /**
+   * @brief Retrieve a handle to the BidirectionalSupport instance.
+   *
+   * @return A handle to the BidirectionalSupport
+   */
+  static BidirectionalSupport Get();
+
+  /**
+   * @brief Creates bidirectional data for the whole paragraph.
+   *
+   * @param[in] paragraph Pointer to the first character of the paragraph coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters of the paragraph.
+   *
+   * @return An index of an object inside a table storing the bidirectional data.
+   */
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters );
+
+  /**
+   * @brief Destroys the bidirectional data.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   */
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex );
+
+  /**
+   * @brief Reorders a line of a paragraph.
+   *
+   * @pre visualToLogicalMap must have enough space allocated for @p numberOfCharacters.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   * @param[in] firstCharacterIndex The first character of the line within the whole paragraph.
+   * @param[in] numberOfCharacters The number of characters of the line.
+   * @param[out] visualToLogicalMap The visual to logical conversion map.
+   */
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap );
+
+  /**
+   * @brief Replaces any character which could be mirrored.
+   *
+   * @param[in,out] text The text.
+   * @param[in] numberOfCharacters The number of characters.
+   *
+   * @return @e true if a character has been replaced.
+   */
+  bool GetMirroredText( Character* text,
+                        Length numberOfCharacters );
+
+  /**
+   * @brief Retrieves the paragrpah's direction.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   *
+   * @return @e true if the paragraph is right to left, otherwise @e false.
+   */
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const;
+
+  /**
+   * @brief Retrieves the character's directions.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   * @param[out] directions The direction, @e false is left to right and @e true is right to left, of each character of the paragraph.
+   * @param[in] numberOfCharacters The number of characters.
+   */
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H__
diff --git a/text/dali/devel-api/text-abstraction/font-client.cpp b/text/dali/devel-api/text-abstraction/font-client.cpp
new file mode 100644 (file)
index 0000000..997e999
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64
+
+FontClient FontClient::Get()
+{
+  return Internal::FontClient::Get();
+}
+
+FontClient::FontClient()
+{
+}
+
+FontClient::~FontClient()
+{
+}
+
+FontClient::FontClient( const FontClient& handle )
+: BaseHandle( handle )
+{
+}
+
+FontClient& FontClient::operator=( const FontClient& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
+{
+  GetImplementation(*this).SetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi )
+{
+  GetImplementation(*this).GetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::SetDefaultFont( const FontDescription& fontDescription )
+{
+  GetImplementation(*this).SetDefaultFont( fontDescription );
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+  GetImplementation(*this).GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDefaultPlatformFontDescription( fontDescription );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+  GetImplementation(*this).GetSystemFonts( systemFonts );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+  return GetImplementation(*this).GetPointSize( id );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  return GetImplementation(*this).FindDefaultFont( charcode, pointSize, preferColor );
+}
+
+FontId FontClient::FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  return GetImplementation(*this).FindFallbackFont( preferredFont, charcode, pointSize, preferColor );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( path, pointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontDescription& fontDescription,
+                              PointSize26Dot6 pointSize,
+                              FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( fontDescription,
+                                             pointSize,
+                                             faceIndex );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+  return GetImplementation(*this).IsScalable( path );;
+}
+
+bool FontClient::IsScalable( const FontDescription& fontDescription )
+{
+  return GetImplementation(*this).IsScalable( fontDescription );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontDescription& fontDescription,
+                                Dali::Vector< PointSize26Dot6 >& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( fontDescription, sizes );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics, int maxFixedSize )
+{
+  GetImplementation(*this).GetFontMetrics( fontId, metrics, maxFixedSize );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+  return GetImplementation(*this).GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int maxFixedSize )
+{
+  return GetImplementation(*this).GetGlyphMetrics( array, size, horizontal, maxFixedSize );
+}
+
+BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+{
+  return GetImplementation(*this).CreateBitmap( fontId, glyphIndex );
+}
+
+const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 pointSize )
+{
+  return GetImplementation(*this).GetEllipsisGlyph( pointSize );
+}
+
+FontClient::FontClient( Internal::FontClient* internal )
+: BaseHandle( internal )
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/font-client.h b/text/dali/devel-api/text-abstraction/font-client.h
new file mode 100644 (file)
index 0000000..f50adb9
--- /dev/null
@@ -0,0 +1,331 @@
+#ifndef __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__
+#define __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/devel-api/text-abstraction/font-list.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+struct FontMetrics;
+struct GlyphInfo;
+
+namespace Internal DALI_INTERNAL
+{
+class FontClient;
+}
+
+/**
+ * @brief FontClient provides access to font information and resources.
+ *
+ * <h3>Querying the System Fonts</h3>
+ *
+ * A "system font" is described by a "path" to a font file on the native filesystem, along with a "family" and "style".
+ * For example on the Ubuntu system a "Regular" style font from the "Ubuntu Mono" family can be accessed from "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf".
+ *
+ * <h3>Accessing Fonts</h3>
+ *
+ * A "font" is created from the system for a specific point size in 26.6 fractional points. A "FontId" is used to identify each font.
+ * For example two different fonts with point sizes 10 & 12 can be created from the "Ubuntu Mono" family:
+ * @code
+ * FontClient fontClient   = FontClient::Get();
+ * FontId ubuntuMonoTen    = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 10*64 );
+ * FontId ubuntuMonoTwelve = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 12*64 );
+ * @endcode
+ * Glyph metrics and bitmap resources can then be retrieved using the FontId.
+ */
+class DALI_IMPORT_API FontClient : public BaseHandle
+{
+public:
+  static const PointSize26Dot6 DEFAULT_POINT_SIZE; ///< The default point size.
+
+public:
+
+  /**
+   * @brief Retrieve a handle to the FontClient instance.
+   *
+   * @return A handle to the FontClient
+   */
+  static FontClient Get();
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   */
+  FontClient();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~FontClient();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle.
+   */
+  FontClient( const FontClient& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  FontClient& operator=( const FontClient& handle );
+
+  ////////////////////////////////////////
+  // Font management and validation.
+  ////////////////////////////////////////
+
+  /**
+   * @brief Set the DPI of the target window.
+   *
+   * @note Multiple windows are not currently supported.
+   * @param[in] horizontalDpi The horizontal resolution in DPI.
+   * @param[in] verticalDpi The vertical resolution in DPI.
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @brief Retrieves the DPI previously set to the target window.
+   *
+   * @note Multiple windows are not currently supported.
+   * @param[out] horizontalDpi The horizontal resolution in DPI.
+   * @param[out] verticalDpi The vertical resolution in DPI.
+   */
+  void GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi );
+
+  /**
+   * Set the default font family and its style that should be used by the font client.
+   * The style could be a pair 'font style, font width' or a cluster 'font width, font weight, font slant'.
+   *
+   * @param[in] fontDescription Description of the default font.
+   */
+  void SetDefaultFont( const FontDescription& fontDescription );
+
+  /**
+   * @brief Retrieve the list of default fonts supported by the system.
+   *
+   * @param[out] defaultFonts A list of default font paths, family & style strings.
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @brief Retrieve the active default font from the system
+   *
+   * @param[out] fontDescription font structure describing the default font
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @brief Retrieve the list of fonts supported by the system.
+   *
+   * @param[out] systemFonts A list of font paths, family & style strings.
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @brief Retrieves the font description of a given font @p id.
+   *
+   * @param[in] id The font id.
+   * @param[out] fontDescription The path, family & style describing the font.
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription );
+
+  /**
+   * @brief Retrieves the font point size of a given font @p id.
+   *
+   * @param[in] id The font id.
+   *
+   * @return The point size in 26.6 fractional points.
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @brief Find the default font for displaying a UTF-32 character.
+   *
+   * This is useful when localised strings are provided for multiple languages
+   * i.e. when a single default font does not work for all languages.
+   * @param[in] charcode The character for which a font is needed.
+   * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] preferColor True if a color font is preferred.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId FindDefaultFont( Character charcode,
+                          PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE,
+                          bool preferColor = false );
+
+  /**
+   * @brief Find a fallback-font for displaying a UTF-32 character.
+   *
+   * This is useful when localised strings are provided for multiple languages
+   * i.e. when a single default font does not work for all languages.
+   * @param[in] preferredFont The preferred font which may not provide a glyph for charcode.
+   * The fallback-font will be the closest match to preferredFont, which does support the required glyph.
+   * @param[in] charcode The character for which a font is needed.
+   * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] preferColor True if a color font is preferred.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId FindFallbackFont( FontId preferredFont,
+                           Character charcode,
+                           PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE,
+                           bool preferColor = false );
+
+  /**
+   * @brief Retrieve the unique identifier for a font.
+   *
+   * @param[in] path The path to a font file.
+   * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] faceIndex The index of the font face (optional).
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId GetFontId( const FontPath& path,
+                    PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE,
+                    FaceIndex faceIndex = 0 );
+
+  /**
+   * @brief Retrieve the unique identifier for a font.
+   *
+   * @note It the font style is not empty, it will be used instead the font weight and font slant slant.
+   *
+   * @param[in] fontDescription A font description.
+   * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] faceIndex The index of the font face (optional).
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId GetFontId( const FontDescription& fontDescription,
+                    PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE,
+                    FaceIndex faceIndex = 0 );
+
+  /**
+   * @brief Check to see if a font is scalable.
+   *
+   * @param[in] path The path to a font file.
+   * @return true if scalable.
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @brief Check to see if a font is scalable.
+   *
+   * @note It the font style is not empty, it will be used instead the font weight and font slant slant.
+   *
+   * @param[in] fontDescription A font description.
+   *
+   * @return true if scalable
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @brief Get a list of sizes available for a fixed size font.
+   *
+   * @param[in] path The path to a font file.
+   * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @brief Get a list of sizes available for a fixed size font.
+   *
+   * @note It the font style is not empty, it will be used instead the font weight and font slant slant.
+   *
+   * @param[in] fontDescription A font description.
+   * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  ////////////////////////////////////////
+  // Font metrics, glyphs and bitmaps.
+  ////////////////////////////////////////
+
+  /**
+   * @brief Query the metrics for a font.
+   *
+   * @param[in] fontId The ID of the font for the required glyph.
+   * @param[out] metrics The font metrics.
+   * @param[in] maxFixedSize The metrics for fixed-size fonts will be down-scaled, when exceeding this maximum value in pixels.
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics, int maxFixedSize = 0 );
+
+  /**
+   * @brief Retrieve the glyph index for a UTF-32 character code.
+   *
+   * @param[in] fontId The ID of the font for the required glyph.
+   * @param[in] charcode The UTF-32 character code.
+   * @return The glyph index, or zero if the character code is undefined.
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @brief Retrieve the metrics for a series of glyphs.
+   *
+   * @param[in,out] array An array of glyph-info structures with initialized FontId & GlyphIndex values.
+   * It may contain the advance and an offset set into the bearing from the shaping tool.
+   * On return, the glyph's size value will be initialized. The bearing value will be updated by adding the font's glyph bearing to the one set by the shaping tool.
+   * @param[in] size The size of the array.
+   * @param[in] horizontal True for horizontal layouts (set to false for vertical layouting).
+   * @param[in] maxFixedSize The metrics for fixed-size fonts will be down-scaled, when exceeding this maximum value in pixels.
+   * @return True if all of the requested metrics were found.
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal = true, int maxFixedSize = 0 );
+
+  /**
+   * @brief Render a bitmap representation of a glyph.
+   *
+   * @param[in] fontId The ID of the font.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @return A valid BufferImage, or an empty handle if the glyph could not be rendered.
+   */
+  BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @brief Retrieves the ellipsis glyph for a requested point size.
+   *
+   * @param[in] pointSize The requested point size.
+   *
+   * @return The ellipsis glyph.
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize );
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used by FontClient::Get().
+   *
+   * @param[in] fontClient  A pointer to the internal fontClient object.
+   */
+  explicit DALI_INTERNAL FontClient( Internal::FontClient* fontClient );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__
diff --git a/text/dali/devel-api/text-abstraction/font-list.cpp b/text/dali/devel-api/text-abstraction/font-list.cpp
new file mode 100644 (file)
index 0000000..8118f99
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/font-list.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+DALI_IMPORT_API std::ostream& operator<<( std::ostream& o, const FontList& fontList )
+{
+  for( unsigned int i=0; i<fontList.size(); ++i )
+  {
+    const FontDescription& description = fontList[i];
+    o << "Font " << i << ") path: " << description.path << " family: " << " width : " << description.width << " weight : " << description.weight << " slant : " << description.slant << std::endl;
+  }
+
+  return o;
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/font-list.h b/text/dali/devel-api/text-abstraction/font-list.h
new file mode 100644 (file)
index 0000000..46e2438
--- /dev/null
@@ -0,0 +1,124 @@
+#ifndef __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
+#define __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <iostream>
+#include <dali/public-api/common/vector-wrapper.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+typedef std::string FontPath;
+typedef std::string FontFamily;
+typedef std::string FontStyle;
+
+namespace FontWidth
+{
+  /**
+   * @brief Enumeration type for the font's width
+   */
+  enum Type
+  {
+    ULTRA_CONDENSED,
+    EXTRA_CONDENSED,
+    CONDENSED,
+    SEMI_CONDENSED,
+    NORMAL,
+    SEMI_EXPANDED,
+    EXPANDED,
+    EXTRA_EXPANDED,
+    ULTRA_EXPANDED,
+  };
+} // namespace FontWidth
+
+namespace FontWeight
+{
+  /**
+   * @brief Enumeration type for the font's weight
+   */
+  enum Type
+  {
+    THIN,
+    ULTRA_LIGHT,
+    EXTRA_LIGHT = ULTRA_LIGHT,
+    LIGHT,
+    DEMI_LIGHT,
+    SEMI_LIGHT = DEMI_LIGHT,
+    BOOK,
+    NORMAL,
+    REGULAR = NORMAL,
+    MEDIUM,
+    DEMI_BOLD,
+    SEMI_BOLD = DEMI_BOLD,
+    BOLD,
+    ULTRA_BOLD,
+    EXTRA_BOLD = ULTRA_BOLD,
+    BLACK,
+    HEAVY = BLACK,
+    EXTRA_BLACK = BLACK
+  };
+}
+
+namespace FontSlant
+{
+  /**
+   * @brief Enumeration type for the font's slant
+   */
+  enum Type
+  {
+    NORMAL,
+    ROMAN = NORMAL,
+    ITALIC,
+    OBLIQUE
+  };
+} // namespace FontSlant
+
+struct FontDescription
+{
+  FontDescription()
+  : path(),
+    family(),
+    width( FontWidth::NORMAL ),
+    weight( FontWeight::NORMAL ),
+    slant( FontSlant::NORMAL )
+  {}
+
+  ~FontDescription()
+  {}
+
+  FontPath         path;   ///< The font's file name path.
+  FontFamily       family; ///< The font's family name.
+  FontWidth::Type  width;  ///< The font's width.
+  FontWeight::Type weight; ///< The font's weight.
+  FontSlant::Type  slant;  ///< The font's slant.
+};
+
+typedef std::vector<FontDescription> FontList;
+
+DALI_IMPORT_API std::ostream& operator<<( std::ostream& o, const FontList& fontList );
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_TEXT_ABSTRACTION_FONT_LIST_H__
diff --git a/text/dali/devel-api/text-abstraction/font-metrics.cpp b/text/dali/devel-api/text-abstraction/font-metrics.cpp
new file mode 100644 (file)
index 0000000..1edff6d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+FontMetrics::FontMetrics()
+: ascender( 0.f ),
+  descender( 0.f ),
+  height( 0.f ),
+  underlinePosition( 0.f ),
+  underlineThickness( 0.f )
+{
+}
+
+FontMetrics::FontMetrics( float ascenderPixels,
+                          float descenderPixels,
+                          float heightPixels,
+                          float underlinePositionPixels,
+                          float underlineThicknessPixels )
+: ascender( ascenderPixels ),
+  descender( descenderPixels ),
+  height( heightPixels ),
+  underlinePosition( underlinePositionPixels ),
+  underlineThickness( underlineThicknessPixels )
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/font-metrics.h b/text/dali/devel-api/text-abstraction/font-metrics.h
new file mode 100644 (file)
index 0000000..3649dab
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
+#define __DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * The metrics for a Font expressed in pixels.
+ */
+struct DALI_IMPORT_API FontMetrics
+{
+  /**
+   * @brief Default constructor.
+   */
+  FontMetrics();
+
+  /**
+   * @brief Create the font metrics in pixels.
+   */
+  FontMetrics( float ascenderPixels,
+               float descenderPixels,
+               float heightPixels,
+               float underlinePositionPixels,
+               float underlinePositionThickness );
+
+  float ascender;             ///< The ascender in pixels.
+  float descender;            ///< The descender in pixels.
+  float height;               ///< The height in pixels.
+  float underlinePosition;    ///< The underline position in pixels.
+  float underlineThickness;   ///< The vertical height of the underline in pixels.
+};
+
+} // Dali
+
+} // TextAbstraction
+
+#endif //__DALI_TEXT_ABSTRACTION_FONT_METRICS_H__
diff --git a/text/dali/devel-api/text-abstraction/glyph-info.cpp b/text/dali/devel-api/text-abstraction/glyph-info.cpp
new file mode 100644 (file)
index 0000000..2d7c811
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+GlyphInfo::GlyphInfo()
+: fontId( 0 ),
+  index( 0 ),
+  width( 0 ),
+  height( 0 ),
+  xBearing( 0 ),
+  yBearing( 0 ),
+  advance( 0 ),
+  scaleFactor( 0 )
+{
+}
+
+GlyphInfo::GlyphInfo( FontId font, GlyphIndex i )
+: fontId( font ),
+  index( i ),
+  width( 0 ),
+  height( 0 ),
+  xBearing( 0 ),
+  yBearing( 0 ),
+  advance( 0 ),
+  scaleFactor( 0 )
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/glyph-info.h b/text/dali/devel-api/text-abstraction/glyph-info.h
new file mode 100644 (file)
index 0000000..952a302
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef __DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
+#define __DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * The information describing a glyph (font ID, index, metrics)
+ * The metrics are in pixels.
+ */
+struct DALI_IMPORT_API GlyphInfo
+{
+  /**
+   * @brief Default constructor.
+   */
+  GlyphInfo();
+
+  /**
+   * @brief Creates the GlyphInfo without metrics.
+   */
+  GlyphInfo( FontId font, GlyphIndex i );
+
+  FontId fontId;     ///< Identifies the font containing the glyph
+  GlyphIndex index;  ///< Uniquely identifies a glyph for a given FontId
+  float width;       ///< The width of the glyph
+  float height;      ///< The height of the glyph
+  float xBearing;    ///< The distance from the cursor position to the leftmost border of the glyph
+  float yBearing;    ///< The distance from the baseline to the topmost border of the glyph
+  float advance;     ///< The distance to move the cursor for this glyph
+  float scaleFactor; ///< The scaling applied (fixed-size fonts only)
+};
+
+} // Dali
+
+} // TextAbstraction
+
+#endif //__DALI_TEXT_ABSTRACTION_GLYPH_INFO_H__
diff --git a/text/dali/devel-api/text-abstraction/script.cpp b/text/dali/devel-api/text-abstraction/script.cpp
new file mode 100644 (file)
index 0000000..f02a3c3
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/script.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace
+{
+const unsigned int WHITE_SPACE_THRESHOLD  = 0x21; ///< All characters below 0x21 are considered white spaces.
+const unsigned int CHAR_LF   = 0x000A; ///< NL Line feed, new line.
+const unsigned int CHAR_VT   = 0x000B; ///< Vertical tab.
+const unsigned int CHAR_FF   = 0x000C; ///< NP Form feed, new page.
+const unsigned int CHAR_CR   = 0x000D; ///< Carriage return, new line.
+const unsigned int CHAR_NEL  = 0x0085; ///< Next line.
+const unsigned int CHAR_LS   = 0x2028; ///< Line separator.
+const unsigned int CHAR_PS   = 0x2029; ///< Paragraph separator
+
+const unsigned int CHAR_ZWS  = 0x200B; ///< Zero width space.
+const unsigned int CHAR_ZWNJ = 0x200C; ///< Zero width non joiner.
+const unsigned int CHAR_ZWJ  = 0x200D; ///< Zero width joiner.
+const unsigned int CHAR_LTRM = 0x200E; ///< Left to Right Mark.
+const unsigned int CHAR_RTLM = 0x200F; ///< Right to Left Mark.
+const unsigned int CHAR_TS   = 0x2009; ///< Thin Space.
+} // namespace
+
+bool IsRightToLeftScript( Script script )
+{
+  return ( ( ARABIC == script ) ||
+           ( HEBREW == script ) );
+}
+
+Script GetCharacterScript( Character character )
+{
+  // Latin script:
+  // 0x0000 - 0x007f C0 Controls and Basic Latin
+  // 0x0080 - 0x00ff C1 Controls and Latin-1 Supplement
+  // 0x0100 - 0x017f Latin Extended-A
+  // 0x0180 - 0x024f Latin Extended-B
+  // 0x0250 - 0x02af IPA Extensions
+  // 0x02b0 - 0x02ff Spacing Modifier Letters
+  // 0x1d00 - 0x1d7f Phonetic Extensions
+  // 0x1d80 - 0x1dbf Phonetic Extensions Supplement
+  // 0x1e00 - 0x1eff Latin Extended Additional
+  // 0x2070 - 0x209f Superscripts and Subscripts
+  // 0x2100 - 0x214f Letterlike symbols
+  // 0x2150 - 0x218f Number Forms
+  // 0x2c60 - 0x2c7f Latin Extended-C
+  // 0xa720 - 0xa7ff Latin Extended-D
+  // 0xab30 - 0xab6f Latin Extended-E
+  // 0xfb00 - 0xfb06 Latin Alphabetic Presentation Forms
+  // 0xff00 - 0xffef Halfwidth and Fullwidth Forms
+
+  // Brahmic scripts:
+  // 0x0900 - 0x097f Devanagari
+  // 0x0980 - 0x09ff Bengali
+  // 0x0a00 - 0x0a7f Gurmukhi
+  // 0x0a80 - 0x0aff Gujarati
+  // 0x0b00 - 0x0b7f Oriya
+  // 0x0b80 - 0x0bff Tamil
+  // 0x0c00 - 0x0c7f Telugu
+  // 0x0c80 - 0x0cff Kannada
+  // 0x0d00 - 0x0d7f Malayalam
+
+  // Sinhala script.
+  // 0x0d80 - 0x0dff Sinhala
+
+  // Arabic script.
+  // 0x0600 - 0x06ff Arabic
+  // 0x0750 - 0x077f Arabic Supplement
+  // 0x08A0 - 0x08ff Arabic Extended-A
+  // 0xfb50 - 0xfdff Arabic Presentation Forms-A
+  // 0xfe70 - 0xfeff Arabic Presentation Forms-B
+  // 0x1ee00 - 0x1eeff Arabic Mathematical Alphabetic Symbols
+
+  // CJK (Chinese, Japanese and Korean) and Vietnamese script.
+  // 0x2e80 - 0x2eff CJK Radicals Supplement
+  // 0x2f00 - 0x2fdf Kangxi Radicals
+  // 0x3000 - 0x303f CJK Symbols and Punctuation
+  // 0x3200 - 0x32ff Enclosed CJK Letters and Months
+  // 0x3400 - 0x4dbf CJK Unified Ideographs Extension A
+  // 0x4e00 - 0x62ff CJK Unified Ideographs
+  // 0x6300 - 0x77ff CJK Unified Ideographs
+  // 0x7800 - 0x8cff CJK Unified Ideographs
+  // 0x8d00 - 0x9fff CJK Unified Ideographs
+  // 0x20000 - 0x215ff CJK Unified Ideographs Extension B
+  // 0x21600 - 0x230ff CJK Unified Ideographs Extension B
+  // 0x23100 - 0x245ff CJK Unified Ideographs Extension B
+  // 0x24600 - 0x260ff CJK Unified Ideographs Extension B
+  // 0x26100 - 0x275ff CJK Unified Ideographs Extension B
+  // 0x27600 - 0x290ff CJK Unified Ideographs Extension B
+  // 0x29100 - 0x2a6df CJK Unified Ideographs Extension B
+  // 0x2a700 - 0x2b73f CJK Unified Ideographs Extension C
+  // 0x2b740 - 0x2b81f CJK Unified Ideographs Extension D
+
+  // Japanese scripts.
+  // 0x3040 - 0x309f Hiragana
+  // 0x30a0 - 0x30ff Katakana
+
+  // Hangul script
+  // 0x1100 - 0x11ff Hangul jamo
+  // 0x3130 - 0x318f Hangul Compatibility Jamo
+  // 0xa960 - 0xa97f Hangul Jamo Extended-A
+  // 0xac00 - 0xd7af Hangul Syllables
+  // 0xd7b0 - 0xd7ff Hangul Jamo Extended-B
+
+  // Bopomofo script
+  // 0x3100 - 0x312f Bopomofo
+  // 0x31a0 - 0x31bf Bopomofo Extended
+
+  // Khmer script
+  // 0x1780 - 0x17ff Khmer
+  // 0x19e0 - 0x19ff Khmer Symbols
+
+  // Lao script
+  // 0x0e80 - 0x0eff Lao
+
+  // Thai script
+  // 0x0e00 - 0x0e7f Thai
+
+  // Burmese script
+  // 0x1000 - 0x109f Myanmar
+
+  // Hebrew script
+  // 0x0591 - 0x05f4 Hebrew
+  // 0xfb1d - 0xfb4f Hebrew subset of Alphabetic Presentation Forms
+
+  // Cyrillic script
+  // 0x0400 - 0x04ff Cyrillic
+  // 0x0500 - 0x052f Cyrillic suplement
+  // 0x2de0 - 0x2dff Cyrillic Extended-A
+  // 0xa640 - 0xa69f Cyrillic Extended-B
+
+  // Georgian script
+  // 0x10a0 - 0x10ff Georgian
+  // 0x2d00 - 0x2d2f Georgian suplement
+
+  // Greek script
+  // 0x0370 - 0x03ff Greek & Coptic
+  // 0x1f00 - 0x1fff Greek Extended
+
+  // Armenian script
+  // 0x0530 - 0x058f Armenian
+  // 0xfb13 - 0xfb17 Armenian subset of Alphabetic prefentation forms
+
+  // The Emoji which map to standardized Unicode characters
+  // 1. Emoticons ( 1F601 - 1F64F )
+  // 2. Dingbats ( 2702 - 27B0 )
+  // 3. Transport and map symbols ( 1F680 - 1F6C0 )
+  // 4. Enclosed characters ( 24C2 - 1F251 )
+  // 5. Uncategorized :-S
+  // 6. Additional Emoticons ( 1F600 - 1F636 )
+  // 6b. Additional transport and map symbols ( 1F681 - 1F6C5 )
+  // 6c. Other additional symbols ( 1F30D - 1F567 )
+
+  // Symbols. Work around for these symbols.
+  // 0x25cb
+  // 0x25cf
+  // 0x25a1
+  // 0x25a0
+  // 0x2664
+  // 0x2661
+  // 0x2662
+  // 0x2667
+  // 0x2606
+  // 0x25aa
+  // 0x262a
+
+  if( IsCommonScript( character ) )
+  {
+    return COMMON;
+  }
+
+  if( character <= 0x0cff )
+  {
+    if( character <= 0x09ff )
+    {
+      if( character <= 0x077f )
+      {
+        if( character == 0x00A9 )
+        {
+          return EMOJI; // 5. Uncategorized: copyright sign
+        }
+        if( character == 0x00AE )
+        {
+          return EMOJI; // 5. Uncategorized: registered sign
+        }
+        if( character <= 0x02ff )
+        {
+          return LATIN;
+        }
+        if( ( 0x0370 <= character ) && ( character <= 0x03ff ) )
+        {
+          return GREEK;
+        }
+        if( ( 0x0400 <= character ) && ( character <= 0x04ff ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x0500 <= character ) && ( character <= 0x052f ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x0530 <= character ) && ( character <= 0x058f ) )
+        {
+          return ARMENIAN;
+        }
+        if( ( 0x0591 <= character ) && ( character <= 0x05f4 ) )
+        {
+          return HEBREW;
+        }
+        if( ( 0x0600 <= character ) && ( character <= 0x06ff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0x0750 <= character ) && ( character <= 0x077f ) )
+        {
+          return ARABIC;
+        }
+      }
+      else // > 0x077f
+      {
+        if( ( 0x08A0 <= character ) && ( character <= 0x08ff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0x0900 <= character ) && ( character <= 0x097f ) )
+        {
+          return DEVANAGARI;
+        }
+        if( ( 0x0980 <= character ) && ( character <= 0x09ff ) )
+        {
+          return BENGALI;
+        }
+      }
+    }
+    else // > 0x09ff
+    {
+      if( character <= 0x0b7f )
+      {
+        if( ( 0x0a00 <= character ) && ( character <= 0x0a7f ) )
+        {
+          return GURMUKHI;
+        }
+        if( ( 0x0a80 <= character ) && ( character <= 0x0aff ) )
+        {
+          return GUJARATI;
+        }
+        if( ( 0x0b00 <= character ) && ( character <= 0x0b7f ) )
+        {
+          return ORIYA;
+        }
+      }
+      else // > 0x0b7f
+      {
+        if( ( 0x0b80 <= character ) && ( character <= 0x0bff ) )
+        {
+          return TAMIL;
+        }
+        if( ( 0x0c00 <= character ) && ( character <= 0x0c7f ) )
+        {
+          return TELUGU;
+        }
+        if( ( 0x0c80 <= character ) && ( character <= 0x0cff ) )
+        {
+          return KANNADA;
+        }
+      }
+    }
+  }
+  else // > 0x0cff
+  {
+    if( character <= 0x2c7f )
+    {
+      if( character <= 0x1eff )
+      {
+        if( ( 0x0d00 <= character ) && ( character <= 0x0d7f ) )
+        {
+          return MALAYALAM;
+        }
+        if( ( 0x0d80 <= character ) && ( character <= 0x0dff ) )
+        {
+          return SINHALA;
+        }
+        if( ( 0x0e00 <= character ) && ( character <= 0x0e7f ) )
+        {
+          return THAI;
+        }
+        if( ( 0x0e80 <= character ) && ( character <= 0x0eff ) )
+        {
+          return LAO;
+        }
+        if( ( 0x1000 <= character ) && ( character <= 0x109f ) )
+        {
+          return BURMESE;
+        }
+        if( ( 0x10a0 <= character ) && ( character <= 0x10ff ) )
+        {
+          return GEORGIAN;
+        }
+        if( ( 0x1100 <= character ) && ( character <= 0x11ff ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0x1780 <= character ) && ( character <= 0x17ff ) )
+        {
+          return KHMER;
+        }
+        if( ( 0x19e0 <= character ) && ( character <= 0x19ff ) )
+        {
+          return KHMER;
+        }
+        if( ( 0x1d00 <= character ) && ( character <= 0x1eff ) )
+        {
+          return LATIN;
+        }
+      }
+      else // > 0x1eff
+      {
+        if( ( 0x1f00 <= character ) && ( character <= 0x1fff ) )
+        {
+          return GREEK;
+        }
+        if( character == 0x203c )
+        {
+          return EMOJI; // 5. Uncategorized: double exclamation mark
+        }
+        if( character == 0x2049 )
+        {
+          return EMOJI; // 5. Uncategorized: exclamation question mark
+        }
+        if( ( 0x2070 <= character ) && ( character <= 0x209f ) )
+        {
+          return LATIN;
+        }
+        if( character == 0x20e3 )
+        {
+          return EMOJI; // 5. Uncategorized: combining enclosing keycap
+        }
+        if( character == 0x2122 )
+        {
+          return EMOJI; // 5. Uncategorized: trade mark sign
+        }
+        if( character == 0x2139 )
+        {
+          return EMOJI; // 5. Uncategorized: information source
+        }
+        if( ( 0x2100 <= character ) && ( character <= 0x218f ) )
+        {
+          return LATIN;
+        }
+
+        // Symbols
+        if( ( 0x25cb == character ) ||
+            ( 0x25cf == character ) ||
+            ( 0x25a1 == character ) )
+        {
+          return SYMBOLS1;
+        }
+
+        if( 0x25a0 == character )
+        {
+          return SYMBOLS2;
+        }
+
+        if( ( 0x2664 == character ) ||
+            ( 0x2661 == character ) ||
+            ( 0x2662 == character ) ||
+            ( 0x2667 == character ) )
+        {
+          return SYMBOLS3;
+        }
+
+        if( ( 0x2606 == character ) ||
+            ( 0x25aa == character ) )
+        {
+          return SYMBOLS4;
+        }
+
+        if( 0x262a == character )
+        {
+          return SYMBOLS5;
+        }
+
+        // U+2194 5. Uncategorized: left right arrow
+        // U+2B55 5. Uncategorized: heavy large circle
+        if( ( 0x2194 <= character ) && ( character <= 0x2B55 ) )
+        {
+          return EMOJI;
+        }
+        if( ( 0x2c60 <= character ) && ( character <= 0x2c7f ) )
+        {
+          return LATIN;
+        }
+      }
+    }
+    else // > 0x2c7f
+    {
+      if( character <= 0xfdff )
+      {
+        if( ( 0x2d00 <= character ) && ( character <= 0x2d2f ) )
+        {
+          return GEORGIAN;
+        }
+        if( ( 0x2de0 <= character ) && ( character <= 0x2dff ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x2e80 <= character ) && ( character <= 0x2eff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2f00 <= character ) && ( character <= 0x2fdf ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3000 <= character ) && ( character <= 0x303f ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3040 <= character ) && ( character <= 0x309f ) )
+        {
+          return HIRAGANA;
+        }
+        if( ( 0x30a0 <= character ) && ( character <= 0x30ff ) )
+        {
+          return KATAKANA;
+        }
+        if( ( 0x3100 <= character ) && ( character <= 0x312f ) )
+        {
+          return BOPOMOFO;
+        }
+        if( ( 0x3130 <= character ) && ( character <= 0x318f ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0x31a0 <= character ) && ( character <= 0x31bf ) )
+        {
+          return BOPOMOFO;
+        }
+        if( ( 0x3200 <= character ) && ( character <= 0x32ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3400 <= character ) && ( character <= 0x4dbf ) )
+        {
+          return CJK;
+        }
+        if( ( 0x4e00 <= character ) && ( character <= 0x62ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x6300 <= character ) && ( character <= 0x77ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x7800 <= character ) && ( character <= 0x8cff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x8d00 <= character ) && ( character <= 0x9fff ) )
+        {
+          return CJK;
+        }
+        if( ( 0xa640 <= character ) && ( character <= 0xa69f ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0xa720 <= character ) && ( character <= 0xa7ff ) )
+        {
+          return LATIN;
+        }
+        if( ( 0xa960 <= character ) && ( character <= 0xa97f ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xab30 <= character ) && ( character <= 0xab6f ) )
+        {
+          return LATIN;
+        }
+        if( ( 0xac00 <= character ) && ( character <= 0xd7af ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xd7b0 <= character ) && ( character <= 0xd7ff ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xfb00 <= character ) && ( character <= 0xfb06 ) )
+        {
+          return LATIN;
+        }
+        if( ( 0xfb13 <= character ) && ( character <= 0xfb17 ) )
+        {
+          return ARMENIAN;
+        }
+        if( ( 0xfb1d <= character ) && ( character <= 0xfb4f ) )
+        {
+          return HEBREW;
+        }
+        if( ( 0xfb50 <= character ) && ( character <= 0xfdff ) )
+        {
+          return ARABIC;
+        }
+      }
+      else // > 0xfdff
+      {
+        if( ( 0xfe70 <= character ) && ( character <= 0xfeff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0xff00 <= character ) && ( character <= 0xffef ) )
+        {
+          return LATIN;
+        }
+        if( ( 0x1ee00 <= character ) && ( character <= 0x1eeff ) )
+        {
+          return ARABIC;
+        }
+        // U+1f170 4. Enclosed characters: negative squared latin capital letter A
+        // U+1f6c5 6b. Additional transport and map symbols
+        if( ( 0x1f170 <= character ) && ( character <= 0x1f6c5 ) )
+        {
+          return EMOJI;
+        }
+        if( ( 0x20000 <= character ) && ( character <= 0x215ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x21600 <= character ) && ( character <= 0x230ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x23100 <= character ) && ( character <= 0x245ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x24600 <= character ) && ( character <= 0x260ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x26100 <= character ) && ( character <= 0x275ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x27600 <= character ) && ( character <= 0x290ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x29100 <= character ) && ( character <= 0x2a6df ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2a700 <= character ) && ( character <= 0x2b73f ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2b740 <= character ) && ( character <= 0x2b81f ) )
+        {
+          return CJK;
+        }
+      }
+    }
+  }
+
+  return UNKNOWN;
+}
+
+bool IsWhiteSpace( Character character )
+{
+  return character < WHITE_SPACE_THRESHOLD;
+}
+
+bool IsNewParagraph( Character character )
+{
+  return ( ( CHAR_LF == character )  ||
+           ( CHAR_VT == character )  ||
+           ( CHAR_FF == character )  ||
+           ( CHAR_CR == character )  ||
+           ( CHAR_NEL == character ) ||
+           ( CHAR_LS == character )  ||
+           ( CHAR_PS == character ) );
+}
+
+bool IsZeroWidthNonJoiner( Character character )
+{
+  return CHAR_ZWNJ == character;
+}
+
+bool IsZeroWidthJoiner( Character character )
+{
+  return CHAR_ZWJ == character;
+}
+
+bool IsZeroWidthSpace( Character character )
+{
+  return CHAR_ZWS == character;
+}
+
+bool IsLeftToRightMark( Character character )
+{
+  return CHAR_LTRM == character;
+}
+
+bool IsRightToLeftMark( Character character )
+{
+  return CHAR_RTLM == character;
+}
+
+bool IsThinSpace( Character character )
+{
+  return CHAR_TS == character;
+}
+
+bool IsCommonScript( Character character )
+{
+  return ( IsWhiteSpace( character )         ||
+           IsZeroWidthNonJoiner( character ) ||
+           IsZeroWidthJoiner( character )    ||
+           IsZeroWidthSpace( character )     ||
+           IsLeftToRightMark( character )    ||
+           IsRightToLeftMark( character )    ||
+           IsThinSpace( character )          ||
+           IsNewParagraph( character ) );
+}
+
+bool HasLigatureMustBreak( Script script )
+{
+  return ( ( LATIN == script ) ||
+           ( ARABIC == script ) );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/script.h b/text/dali/devel-api/text-abstraction/script.h
new file mode 100644 (file)
index 0000000..d562168
--- /dev/null
@@ -0,0 +1,244 @@
+#ifndef __DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H__
+#define __DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Script is the writing system used by a language.
+ * Typically one script can be used to write different languages although one language could be written in different scrips.
+ */
+enum Script
+{
+  COMMON,     ///< Valid for all scripts. i.e white space or '\n'.
+
+  CYRILLIC,   ///< The Cyrillic script. Used by Russian, Bulgarian, Ukrainian, Macedonian, ...
+  GREEK,      ///< The Greek script. Used by Greek.
+  LATIN,      ///< The latin script. Used by many western languages and others around the world.
+
+  ARABIC,     ///< The arabic script. Used by Arab and Urdu among others.
+  HEBREW,     ///< The Hebrew script. Used by the Hebrew, Yiddish, Ladino, and Judeo-Arabic.
+
+  ARMENIAN,   ///< The Armenian script. Used by Armenian.
+  GEORGIAN,   ///< The Georgian script. Used by Georgian.
+
+  CJK,        ///< The CJK script. Used by Chinese, Japanese, Korean and Vietnamese(old writing system).
+  HANGUL,     ///< The Hangul jamo script. Used by Korean.
+  HIRAGANA,   ///< The Hiragana script. Used by the Japanese.
+  KATAKANA,   ///< The Katakana script. Used by the Japanese.
+  BOPOMOFO,   ///< The Bopomofo script. Also called Zhuyin fuhao or Zhuyin. A phonetic notation used for the transcription of spoken Chinese.
+
+  BENGALI,    ///< The Bengali script. Used by Bangla, Assamese, Bishnupriya Manipuri, Daphla, Garo, Hallam, Khasi, Mizo, Munda, Naga, Rian, and Santali.
+  BURMESE,    ///< The Burmese script. Used by the Burmese (Myanmar) language.
+  DEVANAGARI, ///< The devanagari script. Used by Hindi, Marathi, Sindhi, Nepali and Sanskrit.
+  GUJARATI,   ///< The Gujarati script. Used by Gujarati.
+  GURMUKHI,   ///< The Gurmukhi script. Used by Punjabi.
+  KANNADA,    ///< The Kannada script. Used by Kannada and Tulu.
+  MALAYALAM,  ///< The Malayalam script. Used by Malayalam.
+  ORIYA,      ///< The Oriya script. Used by Oriya (Odia), Khondi, and Santali.
+  SINHALA,    ///< The Sinhala script. Used by Sinhala and Pali.
+  TAMIL,      ///< The Tamil script. Used by Tamil, Badaga, and Saurashtra.
+  TELUGU,     ///< The Telugu script. Used by Telugu, Gondi, and Lambadi.
+
+  LAO,        ///< The Lao script. Used by the Lao language.
+  THAI,       ///< The Thai script. Used by the Thai language
+  KHMER,      ///< The Khmer script. Used by the Khmer language.
+
+  EMOJI,      ///< The Emoji which map to standardized Unicode characters.
+
+  SYMBOLS1,    ///< Some symbols.
+  SYMBOLS2,    ///< Some symbols.
+  SYMBOLS3,    ///< Some symbols.
+  SYMBOLS4,    ///< Some symbols.
+  SYMBOLS5,    ///< Some symbols.
+
+  UNKNOWN     ///< The script is unknown.
+};
+
+const char* const ScriptName[] =
+{
+  "COMMON",     ///< Valid for all scripts. i.e white space or '\n'.
+
+  "CYRILLIC",   ///< The Cyrillic script. Used by Russian, Bulgarian, Ukrainian, Macedonian, ...
+  "GREEK",      ///< The Greek script. Used by Greek.
+  "LATIN",      ///< The latin script. Used by many western languages and others around the world.
+
+  "ARABIC",     ///< The arabic script. Used by Arab and Urdu among others.
+  "HEBREW",     ///< The Hebrew script. Used by the Hebrew, Yiddish, Ladino, and Judeo-Arabic.
+
+  "ARMENIAN",   ///< The Armenian script. Used by Armenian.
+  "GEORGIAN",   ///< The Georgian script. Used by Georgian.
+
+  "CJK",        ///< The CJK script. Used by Chinese, Japanese, Korean and Vietnamese(old writing system).
+  "HANGUL",     ///< The Hangul jamo script. Used by Korean.
+  "HIRAGANA",   ///< The Hiragana script. Used by the Japanese.
+  "KATAKANA",   ///< The Katakana script. Used by the Japanese.
+  "BOPOMOFO",   ///< The Bopomofo script. Also called Zhuyin fuhao or Zhuyin. A phonetic notation used for the transcription of spoken Chinese.
+
+  "BENGALI",    ///< The Bengali script. Used by Bangla, Assamese, Bishnupriya Manipuri, Daphla, Garo, Hallam, Khasi, Mizo, Munda, Naga, Rian, and Santali.
+  "BURMESE",    ///< The Burmese script. Used by the Burmese (Myanmar) language.
+  "DEVANAGARI", ///< The devanagari script. Used by Hindi, Marathi, Sindhi, Nepali and Sanskrit.
+  "GUJARATI",   ///< The Gujarati script. Used by Gujarati.
+  "GURMUKHI",   ///< The Gurmukhi script. Used by Punjabi.
+  "KANNADA",    ///< The Kannada script. Used by Kannada and Tulu.
+  "MALAYALAM",  ///< The Malayalam script. Used by Malayalam.
+  "ORIYA",      ///< The Oriya script. Used by Oriya (Odia), Khondi, and Santali.
+  "SINHALA",    ///< The Sinhala script. Used by Sinhala and Pali.
+  "TAMIL",      ///< The Tamil script. Used by Tamil, Badaga, and Saurashtra.
+  "TELUGU",     ///< The Telugu script. Used by Telugu, Gondi, and Lambadi.
+
+  "LAO",        ///< The Lao script. Used by the Lao language.
+  "THAI",       ///< The Thai script. Used by the Thai language
+  "KHMER",      ///< The Khmer script. Used by the Khmer language.
+
+  "EMOJI",      ///< The Emoji which map to standardized Unicode characters.
+  "SYMBOLS1",    ///< Some symbols.
+  "SYMBOLS2",    ///< Some symbols.
+  "SYMBOLS3",    ///< Some symbols.
+  "SYMBOLS4",    ///< Some symbols.
+  "SYMBOLS5",    ///< Some symbols.
+
+  "UNKNOWN"     ///< The script is unknown.
+};
+
+/**
+ * @brief Whether the script is a right to left script.
+ *
+ * @param[in] script The script.
+ *
+ * @return @e true if the script is right to left.
+ */
+DALI_IMPORT_API bool IsRightToLeftScript( Script script );
+
+/**
+ * @brief Retrieves a character's script.
+ *
+ * @param[in] character The character.
+ *
+ * @return The chraracter's script.
+ */
+DALI_IMPORT_API Script GetCharacterScript( Character character );
+
+/**
+ * @brief Whether the character is a white space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a white space.
+ */
+DALI_IMPORT_API bool IsWhiteSpace( Character character );
+
+/**
+ * @brief Whether the character is a new paragraph character.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a new paragraph character.
+ */
+DALI_IMPORT_API bool IsNewParagraph( Character character );
+
+/**
+ * @brief Whether the character is a zero width non joiner.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width non joiner.
+ */
+DALI_IMPORT_API bool IsZeroWidthNonJoiner( Character character );
+
+/**
+ * @brief Whether the character is a zero width joiner.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width joiner.
+ */
+DALI_IMPORT_API bool IsZeroWidthJoiner( Character character );
+
+/**
+ * @brief Whether the character is a zero width space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width space.
+ */
+DALI_IMPORT_API bool IsZeroWidthSpace( Character character );
+
+/**
+ * @brief Whether the character is a left to right mark.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a left to right mark.
+ */
+DALI_IMPORT_API bool IsLeftToRightMark( Character character );
+
+/**
+ * @brief Whether the character is a right to left mark.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a right to left mark.
+ */
+DALI_IMPORT_API bool IsRightToLeftMark( Character character );
+
+/**
+ * @brief Whether the character is a thin space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a thin space.
+ */
+DALI_IMPORT_API bool IsThinSpace( Character character );
+
+/**
+ * @brief Whether the character is common within all scripts.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is common within all scripts.
+ */
+DALI_IMPORT_API bool IsCommonScript( Character character );
+
+/**
+ * @brief Whether the script contains ligatures that must be 'broken' for selection or cursor position.
+ *
+ * i.e The latin script has the 'ff' or 'fi' ligatures that need to be broken to position the cursor
+ * between the two characters. Equally the arabic script has the 'ﻻ' ligature that needs to be broken.
+ *
+ * @param[in] script The script.
+ *
+ * @return @e true if the script has ligatures that must be 'broken'.
+ */
+DALI_IMPORT_API bool HasLigatureMustBreak( Script script );
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H__
diff --git a/text/dali/devel-api/text-abstraction/segmentation.cpp b/text/dali/devel-api/text-abstraction/segmentation.cpp
new file mode 100644 (file)
index 0000000..f49e2c0
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/segmentation.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text-abstraction/segmentation-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+Segmentation::Segmentation()
+{
+}
+
+Segmentation::~Segmentation()
+{
+}
+
+Segmentation::Segmentation( Internal::Segmentation* implementation )
+: BaseHandle( implementation )
+{
+}
+
+Segmentation Segmentation::Get()
+{
+  return Internal::Segmentation::Get();
+}
+
+void Segmentation::GetLineBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          LineBreakInfo* breakInfo )
+{
+  GetImplementation( *this ).GetLineBreakPositions( text,
+                                                    numberOfCharacters,
+                                                    breakInfo );
+}
+
+void Segmentation::GetWordBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          WordBreakInfo* breakInfo )
+{
+  GetImplementation( *this ).GetWordBreakPositions( text,
+                                                    numberOfCharacters,
+                                                    breakInfo );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/segmentation.h b/text/dali/devel-api/text-abstraction/segmentation.h
new file mode 100644 (file)
index 0000000..c9a2282
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef __DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H__
+#define __DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class Segmentation;
+
+} // Internal
+
+} // TextAbstraction
+
+namespace TextAbstraction
+{
+
+/**
+ *   Segmentation API
+ *
+ */
+class DALI_IMPORT_API Segmentation : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   *
+   */
+  Segmentation();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Segmentation();
+
+  /**
+   * @brief This constructor is used by Segmentation::Get().
+   *
+   * @param[in] implementation A pointer to the internal segmentation object.
+   */
+  explicit DALI_INTERNAL Segmentation( Internal::Segmentation* implementation );
+
+  /**
+   * @brief Retrieve a handle to the Segmentation instance.
+   *
+   * @return A handle to the Segmentation
+   */
+  static Segmentation Get();
+
+  /**
+   * @brief Retrieves the line break info.
+   *
+   * @pre @p breakInfo must have enough space allocated for @p numberOfCharacters.
+   *
+   * Possible values for LineBreakInfo are:
+   *
+   *  - 0 is a LINE_MUST_BREAK.  Text must be broken into a new line.
+   *  - 1 is a LINE_ALLOW_BREAK. Is possible to break the text into a new line.
+   *  - 2 is a LINE_NO_BREAK.    Text can't be broken into a new line.
+   *
+     @verbatim
+     i.e. Hello big\nworld produces:
+          2222212220 22220
+     @endverbatim
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[out] breakInfo The line break info.
+   */
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo );
+
+  /**
+   * @brief Retrieves the word break info.
+   *
+   * @pre @p breakInfo must have enough space allocated for @p numberOfCharacters.
+   *
+   * Possible values for WordBreakInfo are:
+   *
+   * - 0 is a WORD_BREAK.    Text can be broken into a new word.
+   * - 1 is a WORD_NO_BREAK. Text can't be broken into a new word.
+   *
+     @verbatim
+     i.e. Hello big\nworld produces:
+          1111001100 11110
+     @endverbatim
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[out] breakInfo The word break info.
+   */
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H__
diff --git a/text/dali/devel-api/text-abstraction/shaping.cpp b/text/dali/devel-api/text-abstraction/shaping.cpp
new file mode 100644 (file)
index 0000000..f660d74
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text-abstraction/shaping-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+Shaping::Shaping()
+{
+}
+
+Shaping::~Shaping()
+{
+}
+
+Shaping::Shaping( Internal::Shaping *impl )
+: BaseHandle( impl )
+{
+}
+
+Shaping Shaping::Get()
+{
+  return Internal::Shaping::Get();
+}
+
+Length Shaping::Shape( const Character* const text,
+                       Length numberOfCharacters,
+                       FontId fontId,
+                       Script script )
+{
+  return GetImplementation( *this ).Shape( text,
+                                           numberOfCharacters,
+                                           fontId,
+                                           script );
+}
+
+void Shaping::GetGlyphs( GlyphInfo* glyphInfo,
+                         CharacterIndex* glyphToCharacterMap )
+{
+  GetImplementation( *this ).GetGlyphs( glyphInfo,
+                                        glyphToCharacterMap );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/devel-api/text-abstraction/shaping.h b/text/dali/devel-api/text-abstraction/shaping.h
new file mode 100644 (file)
index 0000000..9d72142
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef __DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H__
+#define __DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/script.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+struct GlyphInfo;
+
+namespace Internal DALI_INTERNAL
+{
+
+class Shaping;
+
+} // Internal
+
+/**
+ * @brief Shaping provides an interface to retrieve glyphs from complex text.
+ *
+ * This module shapes text for a unique font id and script. If the text contains different fonts and scripts
+ * it needs to be split in runs of consecutive characters with the same font id and script.
+ *
+ * @code
+ * Shaping shaping = Shaping::Get();
+ *
+ * // Shapes a number of characters with the given font id and script.
+ * const Length numberOfGlyphs = shaping.Shape( text, numberOfCharacters, fontId, script );
+ *
+ * // Allocate memory to retrieve the glyphs and the character to glyph conversion map.
+ * GlyphInfo* glyphInfo = reinterpret_cast<GlyphInfo*>( malloc( numberOfGlyphs * sizeof( GlyphInfo ) ) );
+ * CharacterIndex* glyphToCharacterMap = reinterpret_cast<CharacterIndex*>( malloc( numberOfGlyphs * sizeof( CharacterIndex ) ) );
+ *
+ * // Retrieve the glyphs and the conversion map.
+ * shaping.GetGlyphs( glyphInfo, glyphToCharacterMap );
+ * @endcode
+ */
+class DALI_IMPORT_API Shaping : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized Shaping handle.
+   *
+   */
+  Shaping();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Shaping();
+
+  /**
+   * @brief This constructor is used by Shaping::Get().
+   *
+   * @param[in] implementation A pointer to the internal shaping object.
+   */
+  explicit DALI_INTERNAL Shaping( Internal::Shaping* implementation );
+
+  /**
+   * @brief Retrieve a handle to the Shaping instance.
+   *
+   * @return A handle to the Shaping.
+   */
+  static Shaping Get();
+
+  /**
+   * Shapes the text.
+   *
+   * Call GetGlyphs() to retrieve the glyphs.
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters to be shaped
+   * @param[in] fontId The font to be used to shape the text.
+   * @param[in] script The text's script.
+   *
+   * @return The size of the buffer required to get the shaped text.
+   */
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script );
+
+  /**
+   * Gets the shaped text data.
+   *
+   * @pre @p glyphInfo and @p glyphToCharacterMap must have enough space allocated for the number of glyphs.
+   * Call first Shape() to shape the text and get the number of glyphs.
+   *
+   * @param[out] glyphInfo Vector with indices to the glyph within the font, glyph's metrics and advance.
+   * @param[out] glyphToCharacterMap The glyph to character conversion map.
+   */
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H__
diff --git a/text/dali/devel-api/text-abstraction/text-abstraction-definitions.h b/text/dali/devel-api/text-abstraction/text-abstraction-definitions.h
new file mode 100644 (file)
index 0000000..1bbc1e4
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef __DALI_TEXT_ABSTRACTION_DEFINITIONS_H__
+#define __DALI_TEXT_ABSTRACTION_DEFINITIONS_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+typedef uint32_t FontId;             ///< The unique identifier for a font face (generated by FontClient)
+typedef uint32_t PointSize26Dot6;    ///< The point size in 26.6 fractional points
+typedef uint32_t FaceIndex;          ///< Used with fonts which allow several font faces
+typedef uint32_t GlyphIndex;         ///< Uniquely identifies a glyph within a particular font
+typedef uint32_t Character;          ///< A UTF-32 representation of a character
+typedef uint32_t CharacterIndex;     ///< An index into an array of characters
+typedef uint32_t Length;             ///< The length of an array
+typedef uint32_t BidiInfoIndex;      ///< Index to the bidirectional info for a paragraph.
+typedef char     LineBreakInfo;      ///< Line break info (must break, allow break, no break).
+typedef char     WordBreakInfo;      ///< Word break info (break, no break).
+typedef bool     CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
+
+/**
+ * @brief Enumerates the possible line break info values.
+ */
+enum
+{
+  LINE_MUST_BREAK  = 0u, ///< Text must be broken into a new line.
+  LINE_ALLOW_BREAK = 1u, ///< Is possible to break the text into a new line.
+  LINE_NO_BREAK    = 2u  ///< Text can't be broken into a new line.
+};
+
+/**
+ * @brief Enumerates the possible word break info values.
+ */
+enum
+{
+  WORD_BREAK    = 0u, ///< Text can be broken into a new word.
+  WORD_NO_BREAK = 1u, ///< Text can't be broken into a new word.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_TEXT_ABSTRACTION_DEFINITIONS_H__
diff --git a/text/dali/devel-api/text-abstraction/text-abstraction.h b/text/dali/devel-api/text-abstraction/text-abstraction.h
new file mode 100644 (file)
index 0000000..adc9b2b
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __DALI_TEXT_ABSTRACTION_H__
+#define __DALI_TEXT_ABSTRACTION_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/script.h>
+#include <dali/devel-api/text-abstraction/segmentation.h>
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+#endif //__DALI_TEXT_ABSTRACTION_H__
diff --git a/text/dali/internal/libunibreak/AUTHORS b/text/dali/internal/libunibreak/AUTHORS
new file mode 100644 (file)
index 0000000..1b4f4b4
--- /dev/null
@@ -0,0 +1,11 @@
+Wu Yongwei.  Designed and implemented the original liblinebreak.
+Current maintainer of libunibreak.
+
+Nikolay Pultsin.  Put forward the original requirements on liblinebreak,
+performed tests, and made a lot of suggestions on the initial versions.
+
+Thomas Klausner.  Autoconfiscated and libtoolized liblinebreak.
+
+Tom Hacohen.  Added word boundaries support.
+
+Petr Filipsky.  Added incremental processing for line-breaking.
diff --git a/text/dali/internal/libunibreak/LICENCE b/text/dali/internal/libunibreak/LICENCE
new file mode 100644 (file)
index 0000000..ceec155
--- /dev/null
@@ -0,0 +1,19 @@
+Copyright (C) 2008-2012 Wu Yongwei <wuyongwei at gmail dot com>
+Copyright (C) 2012 Tom Hacohen <tom dot hacohen at samsung dot com>
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the author be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software.  If you use this software
+   in a product, an acknowledgement in the product documentation would
+   be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
diff --git a/text/dali/internal/libunibreak/README.md b/text/dali/internal/libunibreak/README.md
new file mode 100644 (file)
index 0000000..52cd738
--- /dev/null
@@ -0,0 +1,87 @@
+LIBUNIBREAK
+===========
+
+Overview
+--------
+
+This is the README file for libunibreak, an implementation of the line
+breaking and word breaking algorithms as described in [Unicode Standard
+Annex 14] [1] and [Unicode Standard Annex 29] [2].  Check the project's
+[home page] [3] for up-to-date information.
+
+  [1]: http://www.unicode.org/reports/tr14/tr14-30.html
+  [2]: http://www.unicode.org/reports/tr29/tr29-21.html
+  [3]: https://github.com/adah1972/libunibreak
+
+
+Licence
+-------
+
+This library is released under an open-source licence, the zlib/libpng
+licence.  Please check the file *LICENCE* for details.
+
+Apart from using the algorithm, part of the code is derived from the
+[Unicode Public Data] [4], and the [Unicode Terms of Use] [5] may apply.
+
+  [4]: http://www.unicode.org/Public/
+  [5]: http://www.unicode.org/copyright.html
+
+
+Installation
+------------
+
+There are three ways to build the library:
+
+1. On \*NIX systems supported by the autoconfiscation tools, do the
+   normal
+
+        ./configure
+        make
+        sudo make install
+
+   to build and install both the dynamic and static libraries.  In
+   addition, one may
+   - type `make doc` to generate the doxygen documentation; or
+   - type `make linebreakdata` to regenerate *linebreakdata.c* from
+     *LineBreak.txt*.
+   - type `make wordbreakdata` to regenerate *wordbreakdata.c* from
+     *WordBreakProperty.txt*.
+
+2. On systems where GCC and Binutils are supported, one can type
+
+        cd src
+        cp -p Makefile.gcc Makefile
+        make
+
+   to build the static library.  In addition, one may
+   - type `make debug` or `make release` to explicitly generate the
+     debug or release build;
+   - type `make doc` to generate the doxygen documentation; or
+   - type `make linebreakdata` to regenerate *linebreakdata.c* from
+     *LineBreak.txt*.
+   - type `make wordbreakdata` to regenerate *wordbreakdata.c* from
+     *WordBreakProperty.txt*.
+
+3. On Windows, apart from using method 1 (Cygwin/MSYS) and method 2
+   (MinGW), MSVC can also be used.  Type
+
+        cd src
+        nmake -f Makefile.msvc
+
+   to build the static library.  By default the debug release is built.
+   To build the release version
+
+        nmake -f Makefile.msvc CFG="libunibreak - Win32 Release"
+
+
+Documentation
+-------------
+
+Check the generated document *doc/html/linebreak\_8h.html* and
+*doc/html/wordbreak\_8h.html* in the downloaded file for the public
+interfaces exposed to applications.
+
+
+<!--
+vim:autoindent:expandtab:formatoptions=tcqlmn:textwidth=72:
+-->
diff --git a/text/dali/internal/libunibreak/file.list b/text/dali/internal/libunibreak/file.list
new file mode 100644 (file)
index 0000000..d6b28ad
--- /dev/null
@@ -0,0 +1,7 @@
+# Add local source files here:
+
+static_libraries_libunibreak_src_files = \
+  $(static_libraries_libunibreak_src_dir)/linebreak.c \
+  $(static_libraries_libunibreak_src_dir)/linebreakdata.c \
+  $(static_libraries_libunibreak_src_dir)/linebreakdef.c \
+  $(static_libraries_libunibreak_src_dir)/wordbreak.c
diff --git a/text/dali/internal/libunibreak/linebreak.c b/text/dali/internal/libunibreak/linebreak.c
new file mode 100644 (file)
index 0000000..81c7aa6
--- /dev/null
@@ -0,0 +1,879 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2013 Wu Yongwei <wuyongwei at gmail dot com>
+ * Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 30, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-30.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreak.c
+ *
+ * Implementation of the line breaking algorithm as described in Unicode
+ * Standard Annex 14.
+ *
+ * @version 2.5, 2013/11/14
+ * @author  Wu Yongwei
+ * @author  Petr Filipsky
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+/**
+ * Special value used internally to indicate an undefined break result.
+ */
+#define LINEBREAK_UNDEFINED -1
+
+/**
+ * Size of the second-level index to the line breaking properties.
+ */
+#define LINEBREAK_INDEX_SIZE 40
+
+/**
+ * Version number of the library.
+ */
+const int linebreak_version = LINEBREAK_VERSION;
+
+/**
+ * Enumeration of break actions.  They are used in the break action
+ * pair table below.
+ */
+enum BreakAction
+{
+    DIR_BRK,        /**< Direct break opportunity */
+    IND_BRK,        /**< Indirect break opportunity */
+    CMI_BRK,        /**< Indirect break opportunity for combining marks */
+    CMP_BRK,        /**< Prohibited break for combining marks */
+    PRH_BRK         /**< Prohibited break */
+};
+
+/**
+ * Break action pair table.  This is a direct mapping of Table 2 of
+ * Unicode Standard Annex 14, Revision 30.
+ */
+static enum BreakAction baTable[LBP_RI][LBP_RI] = {
+    {   /* OP */
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        CMP_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK },
+    {   /* CL */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* CP */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* QU */
+        PRH_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* GL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* NS */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* EX */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* SY */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* IS */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* PR */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* PO */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* NU */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* AL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* HL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* ID */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* IN */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* HY */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, DIR_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* BA */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, DIR_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* BB */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* B2 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, PRH_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* ZW */
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* CM */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* WJ */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* H2 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* H3 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* JL */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* JV */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* JT */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* RI */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        IND_BRK },
+};
+
+/**
+ * Struct for the second-level index to the line breaking properties.
+ */
+struct LineBreakPropertiesIndex
+{
+    utf32_t end;                    /**< End coding point */
+    struct LineBreakProperties *lbp;/**< Pointer to line breaking properties */
+};
+
+/**
+ * Second-level index to the line breaking properties.
+ */
+static struct LineBreakPropertiesIndex lb_prop_index[LINEBREAK_INDEX_SIZE] =
+{
+    { 0xFFFFFFFF, lb_prop_default }
+};
+
+/**
+ * Initializes the second-level index to the line breaking properties.
+ * If it is not called, the performance of #get_char_lb_class_lang (and
+ * thus the main functionality) can be pretty bad, especially for big
+ * code points like those of Chinese.
+ */
+void init_linebreak(void)
+{
+    size_t i;
+    size_t iPropDefault;
+    size_t len;
+    size_t step;
+
+    len = 0;
+    while (lb_prop_default[len].prop != LBP_Undefined)
+        ++len;
+    step = len / LINEBREAK_INDEX_SIZE;
+    iPropDefault = 0;
+    for (i = 0; i < LINEBREAK_INDEX_SIZE; ++i)
+    {
+        lb_prop_index[i].lbp = lb_prop_default + iPropDefault;
+        iPropDefault += step;
+        lb_prop_index[i].end = lb_prop_default[iPropDefault].start - 1;
+    }
+    lb_prop_index[--i].end = 0xFFFFFFFF;
+}
+
+/**
+ * Gets the language-specific line breaking properties.
+ *
+ * @param lang  language of the text
+ * @return      pointer to the language-specific line breaking
+ *              properties array if found; \c NULL otherwise
+ */
+static struct LineBreakProperties *get_lb_prop_lang(const char *lang)
+{
+    struct LineBreakPropertiesLang *lbplIter;
+    if (lang != NULL)
+    {
+        for (lbplIter = lb_prop_lang_map; lbplIter->lang != NULL; ++lbplIter)
+        {
+            if (strncmp(lang, lbplIter->lang, lbplIter->namelen) == 0)
+            {
+                return lbplIter->lbp;
+            }
+        }
+    }
+    return NULL;
+}
+
+/**
+ * Gets the line breaking class of a character from a line breaking
+ * properties array.
+ *
+ * @param ch   character to check
+ * @param lbp  pointer to the line breaking properties array
+ * @return     the line breaking class if found; \c LBP_XX otherwise
+ */
+static enum LineBreakClass get_char_lb_class(
+        utf32_t ch,
+        struct LineBreakProperties *lbp)
+{
+    while (lbp->prop != LBP_Undefined && ch >= lbp->start)
+    {
+        if (ch <= lbp->end)
+            return lbp->prop;
+        ++lbp;
+    }
+    return LBP_XX;
+}
+
+/**
+ * Gets the line breaking class of a character from the default line
+ * breaking properties array.
+ *
+ * @param ch  character to check
+ * @return    the line breaking class if found; \c LBP_XX otherwise
+ */
+static enum LineBreakClass get_char_lb_class_default(
+        utf32_t ch)
+{
+    size_t i = 0;
+    while (ch > lb_prop_index[i].end)
+        ++i;
+    assert(i < LINEBREAK_INDEX_SIZE);
+    return get_char_lb_class(ch, lb_prop_index[i].lbp);
+}
+
+/**
+ * Gets the line breaking class of a character for a specific
+ * language.  This function will check the language-specific data first,
+ * and then the default data if there is no language-specific property
+ * available for the character.
+ *
+ * @param ch       character to check
+ * @param lbpLang  pointer to the language-specific line breaking
+ *                 properties array
+ * @return         the line breaking class if found; \c LBP_XX
+ *                 otherwise
+ */
+static enum LineBreakClass get_char_lb_class_lang(
+        utf32_t ch,
+        struct LineBreakProperties *lbpLang)
+{
+    enum LineBreakClass lbcResult;
+
+    /* Find the language-specific line breaking class for a character */
+    if (lbpLang)
+    {
+        lbcResult = get_char_lb_class(ch, lbpLang);
+        if (lbcResult != LBP_XX)
+            return lbcResult;
+    }
+
+    /* Find the generic language-specific line breaking class, if no
+     * language context is provided, or language-specific data are not
+     * available for the specific character in the specified language */
+    return get_char_lb_class_default(ch);
+}
+
+/**
+ * Resolves the line breaking class for certain ambiguous or complicated
+ * characters.  They are treated in a simplistic way in this
+ * implementation.
+ *
+ * @param lbc   line breaking class to resolve
+ * @param lang  language of the text
+ * @return      the resolved line breaking class
+ */
+static enum LineBreakClass resolve_lb_class(
+        enum LineBreakClass lbc,
+        const char *lang)
+{
+    switch (lbc)
+    {
+    case LBP_AI:
+        if (lang != NULL &&
+                (strncmp(lang, "zh", 2) == 0 || /* Chinese */
+                 strncmp(lang, "ja", 2) == 0 || /* Japanese */
+                 strncmp(lang, "ko", 2) == 0))  /* Korean */
+        {
+            return LBP_ID;
+        }
+        else
+        {
+            return LBP_AL;
+        }
+    case LBP_CJ:
+        /* Simplified for `normal' line breaking.  See
+         * <url:http://www.unicode.org/reports/tr14/tr14-30.html#CJ>
+         * for details. */
+        return LBP_ID;
+    case LBP_SA:
+    case LBP_SG:
+    case LBP_XX:
+        return LBP_AL;
+    default:
+        return lbc;
+    }
+}
+
+/**
+ * Treats specially for the first character in a line.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has a valid line break class
+ * @post                  \a lbpCtx->lbcCur has the updated line break class
+ */
+static void treat_first_char(
+        struct LineBreakContext* lbpCtx)
+{
+    switch (lbpCtx->lbcCur)
+    {
+    case LBP_LF:
+    case LBP_NL:
+        lbpCtx->lbcCur = LBP_BK;        /* Rule LB5 */
+        break;
+    case LBP_CB:
+        lbpCtx->lbcCur = LBP_BA;        /* Rule LB20 */
+        break;
+    case LBP_SP:
+        lbpCtx->lbcCur = LBP_WJ;        /* Leading space treated as WJ */
+        break;
+    default:
+        break;
+    }
+}
+
+/**
+ * Tries telling the line break opportunity by simple rules.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has the current line break
+ *                        class; and \a lbpCtx->lbcNew has the line
+ *                        break class for the next character
+ * @post                  \a lbpCtx->lbcCur has the updated line break
+ *                        class
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ *                        if identified; or #LINEBREAK_UNDEFINED if
+ *                        table lookup is needed
+ */
+static int get_lb_result_simple(
+        struct LineBreakContext* lbpCtx)
+{
+    if (lbpCtx->lbcCur == LBP_BK
+        || (lbpCtx->lbcCur == LBP_CR && lbpCtx->lbcNew != LBP_LF))
+    {
+        return LINEBREAK_MUSTBREAK;     /* Rules LB4 and LB5 */
+    }
+
+    switch (lbpCtx->lbcNew)
+    {
+    case LBP_SP:
+        return LINEBREAK_NOBREAK;       /* Rule LB7; no change to lbcCur */
+    case LBP_BK:
+    case LBP_LF:
+    case LBP_NL:
+        lbpCtx->lbcCur = LBP_BK;        /* Mandatory break after */
+        return LINEBREAK_NOBREAK;       /* Rule LB6 */
+    case LBP_CR:
+        lbpCtx->lbcCur = LBP_CR;
+        return LINEBREAK_NOBREAK;       /* Rule LB6 */
+    case LBP_CB:
+        lbpCtx->lbcCur = LBP_BA;
+        return LINEBREAK_ALLOWBREAK;    /* Rule LB20 */
+    default:
+        return LINEBREAK_UNDEFINED;     /* Table lookup is needed */
+    }
+}
+
+/**
+ * Tells the line break opportunity by table lookup.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has the current line break
+ *                        class; \a lbpCtx->lbcLast has the line break
+ *                        class for the last character; and \a
+ *                        lbcCur->lbcNew has the line break class for
+ *                        the next character
+ * @post                  \a lbpCtx->lbcCur has the updated line break
+ *                        class
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ */
+static int get_lb_result_lookup(
+        struct LineBreakContext* lbpCtx)
+{
+    /* TODO: Rule LB21a, as introduced by Revision 28 of UAX#14, is not
+     * yet implemented below. */
+    int brk = LINEBREAK_UNDEFINED;
+    assert(lbpCtx->lbcCur <= LBP_RI);
+    assert(lbpCtx->lbcNew <= LBP_RI);
+    switch (baTable[lbpCtx->lbcCur - 1][lbpCtx->lbcNew - 1])
+    {
+    case DIR_BRK:
+        brk = LINEBREAK_ALLOWBREAK;
+        break;
+    case CMI_BRK:
+    case IND_BRK:
+        brk = (lbpCtx->lbcLast == LBP_SP)
+            ? LINEBREAK_ALLOWBREAK
+            : LINEBREAK_NOBREAK;
+        break;
+    case CMP_BRK:
+        brk = LINEBREAK_NOBREAK;
+        if (lbpCtx->lbcLast != LBP_SP)
+            return brk;                 /* Do not update lbcCur */
+        break;
+    case PRH_BRK:
+        brk = LINEBREAK_NOBREAK;
+        break;
+    }
+    lbpCtx->lbcCur = lbpCtx->lbcNew;
+    return brk;
+}
+
+/**
+ * Initializes line breaking context for a given language.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @param[in]     ch      the first character to process
+ * @param[in]     lang    language of the input
+ * @post                  the line breaking context is initialized
+ */
+void lb_init_break_context(
+        struct LineBreakContext* lbpCtx,
+        utf32_t ch,
+        const char* lang)
+{
+    lbpCtx->lang = lang;
+    lbpCtx->lbpLang = get_lb_prop_lang(lang);
+    lbpCtx->lbcLast = LBP_Undefined;
+    lbpCtx->lbcNew = LBP_Undefined;
+    lbpCtx->lbcCur = resolve_lb_class(
+                        get_char_lb_class_lang(ch, lbpCtx->lbpLang),
+                        lbpCtx->lang);
+    treat_first_char(lbpCtx);
+}
+
+/**
+ * Updates LineBreakingContext for the next code point and returns
+ * the detected break.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @param[in]     ch      Unicode code point
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ * @post                  the line breaking context is updated
+ */
+int lb_process_next_char(
+        struct LineBreakContext* lbpCtx,
+        utf32_t ch )
+{
+    int brk;
+
+    lbpCtx->lbcLast = lbpCtx->lbcNew;
+    lbpCtx->lbcNew = get_char_lb_class_lang(ch, lbpCtx->lbpLang);
+    brk = get_lb_result_simple(lbpCtx);
+    switch (brk)
+    {
+    case LINEBREAK_MUSTBREAK:
+        lbpCtx->lbcCur = resolve_lb_class(lbpCtx->lbcNew, lbpCtx->lang);
+        treat_first_char(lbpCtx);
+        break;
+    case LINEBREAK_UNDEFINED:
+        lbpCtx->lbcNew = resolve_lb_class(lbpCtx->lbcNew, lbpCtx->lang);
+        brk = get_lb_result_lookup(lbpCtx);
+        break;
+    default:
+        break;
+    }
+    return brk;
+}
+
+/**
+ * Gets the next Unicode character in a UTF-8 sequence.  The index will
+ * be advanced to the next complete character, unless the end of string
+ * is reached in the middle of a UTF-8 sequence.
+ *
+ * @param[in]     s    input UTF-8 string
+ * @param[in]     len  length of the string in bytes
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t lb_get_next_char_utf8(
+        const utf8_t *s,
+        size_t len,
+        size_t *ip)
+{
+    utf8_t ch;
+    utf32_t res;
+
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    ch = s[*ip];
+
+    if (ch < 0xC2 || ch > 0xF4)
+    {   /* One-byte sequence, tail (should not occur), or invalid */
+        *ip += 1;
+        return ch;
+    }
+    else if (ch < 0xE0)
+    {   /* Two-byte sequence */
+        if (*ip + 2 > len)
+            return EOS;
+        res = ((ch & 0x1F) << 6) + (s[*ip + 1] & 0x3F);
+        *ip += 2;
+        return res;
+    }
+    else if (ch < 0xF0)
+    {   /* Three-byte sequence */
+        if (*ip + 3 > len)
+            return EOS;
+        res = ((ch & 0x0F) << 12) +
+              ((s[*ip + 1] & 0x3F) << 6) +
+              ((s[*ip + 2] & 0x3F));
+        *ip += 3;
+        return res;
+    }
+    else
+    {   /* Four-byte sequence */
+        if (*ip + 4 > len)
+            return EOS;
+        res = ((ch & 0x07) << 18) +
+              ((s[*ip + 1] & 0x3F) << 12) +
+              ((s[*ip + 2] & 0x3F) << 6) +
+              ((s[*ip + 3] & 0x3F));
+        *ip += 4;
+        return res;
+    }
+}
+
+/**
+ * Gets the next Unicode character in a UTF-16 sequence.  The index will
+ * be advanced to the next complete character, unless the end of string
+ * is reached in the middle of a UTF-16 surrogate pair.
+ *
+ * @param[in]     s    input UTF-16 string
+ * @param[in]     len  length of the string in words
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t lb_get_next_char_utf16(
+        const utf16_t *s,
+        size_t len,
+        size_t *ip)
+{
+    utf16_t ch;
+
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    ch = s[(*ip)++];
+
+    if (ch < 0xD800 || ch > 0xDBFF)
+    {   /* If the character is not a high surrogate */
+        return ch;
+    }
+    if (*ip == len)
+    {   /* If the input ends here (an error) */
+        --(*ip);
+        return EOS;
+    }
+    if (s[*ip] < 0xDC00 || s[*ip] > 0xDFFF)
+    {   /* If the next character is not the low surrogate (an error) */
+        return ch;
+    }
+    /* Return the constructed character and advance the index again */
+    return (((utf32_t)ch & 0x3FF) << 10) + (s[(*ip)++] & 0x3FF) + 0x10000;
+}
+
+/**
+ * Gets the next Unicode character in a UTF-32 sequence.  The index will
+ * be advanced to the next character.
+ *
+ * @param[in]     s    input UTF-32 string
+ * @param[in]     len  length of the string in dwords
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t lb_get_next_char_utf32(
+        const utf32_t *s,
+        size_t len,
+        size_t *ip)
+{
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    return s[(*ip)++];
+}
+
+/**
+ * Sets the line breaking information for a generic input string.
+ *
+ * @param[in]  s             input string
+ * @param[in]  len           length of the input
+ * @param[in]  lang          language of the input
+ * @param[out] brks          pointer to the output breaking data,
+ *                           containing #LINEBREAK_MUSTBREAK,
+ *                           #LINEBREAK_ALLOWBREAK, #LINEBREAK_NOBREAK,
+ *                           or #LINEBREAK_INSIDEACHAR
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+void set_linebreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char)
+{
+    utf32_t ch;
+    struct LineBreakContext lbCtx;
+    size_t posCur = 0;
+    size_t posLast = 0;
+
+    --posLast;  /* To be ++'d later */
+    ch = get_next_char(s, len, &posCur);
+    if (ch == EOS)
+        return;
+    lb_init_break_context(&lbCtx, ch, lang);
+
+    /* Process a line till an explicit break or end of string */
+    for (;;)
+    {
+        for (++posLast; posLast < posCur - 1; ++posLast)
+        {
+            brks[posLast] = LINEBREAK_INSIDEACHAR;
+        }
+        assert(posLast == posCur - 1);
+        ch = get_next_char(s, len, &posCur);
+        if (ch == EOS)
+            break;
+        brks[posLast] = lb_process_next_char(&lbCtx, ch);
+    }
+
+    assert(posLast == posCur - 1 && posCur <= len);
+    /* Break after the last character */
+    brks[posLast] = LINEBREAK_MUSTBREAK;
+    /* When the input contains incomplete sequences */
+    while (posCur < len)
+    {
+        brks[posCur++] = LINEBREAK_INSIDEACHAR;
+    }
+}
+
+/**
+ * Sets the line breaking information for a UTF-8 input string.
+ *
+ * @param[in]  s     input UTF-8 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf8(
+        const utf8_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf8);
+}
+
+/**
+ * Sets the line breaking information for a UTF-16 input string.
+ *
+ * @param[in]  s     input UTF-16 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf16(
+        const utf16_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf16);
+}
+
+/**
+ * Sets the line breaking information for a UTF-32 input string.
+ *
+ * @param[in]  s     input UTF-32 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf32(
+        const utf32_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf32);
+}
+
+/**
+ * Tells whether a line break can occur between two Unicode characters.
+ * This is a wrapper function to expose a simple interface.  Generally
+ * speaking, it is better to use #set_linebreaks_utf32 instead, since
+ * complicated cases involving combining marks, spaces, etc. cannot be
+ * correctly processed.
+ *
+ * @param char1  the first Unicode character
+ * @param char2  the second Unicode character
+ * @param lang   language of the input
+ * @return       one of #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *               #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+int is_line_breakable(
+        utf32_t char1,
+        utf32_t char2,
+        const char* lang)
+{
+    utf32_t s[2];
+    char brks[2];
+    s[0] = char1;
+    s[1] = char2;
+    set_linebreaks_utf32(s, 2, lang, brks);
+    return brks[0];
+}
diff --git a/text/dali/internal/libunibreak/linebreak.h b/text/dali/internal/libunibreak/linebreak.h
new file mode 100644 (file)
index 0000000..94fbca0
--- /dev/null
@@ -0,0 +1,87 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2012 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 30, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-30.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreak.h
+ *
+ * Header file for the line breaking algorithm.
+ *
+ * @version 2.2, 2012/10/06
+ * @author  Wu Yongwei
+ */
+
+#ifndef LINEBREAK_H
+#define LINEBREAK_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LINEBREAK_VERSION   0x0202  /**< Version of the library linebreak */
+extern const int linebreak_version;
+
+#ifndef LINEBREAK_UTF_TYPES_DEFINED
+#define LINEBREAK_UTF_TYPES_DEFINED
+typedef unsigned char   utf8_t;     /**< Type for UTF-8 data points */
+typedef unsigned short  utf16_t;    /**< Type for UTF-16 data points */
+typedef unsigned int    utf32_t;    /**< Type for UTF-32 data points */
+#endif
+
+#define LINEBREAK_MUSTBREAK     0   /**< Break is mandatory */
+#define LINEBREAK_ALLOWBREAK    1   /**< Break is allowed */
+#define LINEBREAK_NOBREAK       2   /**< No break is possible */
+#define LINEBREAK_INSIDEACHAR   3   /**< A UTF-8/16 sequence is unfinished */
+
+void init_linebreak(void);
+void set_linebreaks_utf8(
+        const utf8_t *s, size_t len, const char* lang, char *brks);
+void set_linebreaks_utf16(
+        const utf16_t *s, size_t len, const char* lang, char *brks);
+void set_linebreaks_utf32(
+        const utf32_t *s, size_t len, const char* lang, char *brks);
+int is_line_breakable(utf32_t char1, utf32_t char2, const char* lang);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LINEBREAK_H */
diff --git a/text/dali/internal/libunibreak/linebreakdata.c b/text/dali/internal/libunibreak/linebreakdata.c
new file mode 100644 (file)
index 0000000..1038a14
--- /dev/null
@@ -0,0 +1,2066 @@
+/* The content of this file is generated from:
+# LineBreak-7.0.0.txt
+# Date: 2014-02-28, 23:15:00 GMT [KW, LI]
+*/
+
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+/** Default line breaking properties as from the Unicode Web site. */
+struct LineBreakProperties lb_prop_default[] = {
+       { 0x0000, 0x0008, LBP_CM },
+       { 0x0009, 0x0009, LBP_BA },
+       { 0x000A, 0x000A, LBP_LF },
+       { 0x000B, 0x000C, LBP_BK },
+       { 0x000D, 0x000D, LBP_CR },
+       { 0x000E, 0x001F, LBP_CM },
+       { 0x0020, 0x0020, LBP_SP },
+       { 0x0021, 0x0021, LBP_EX },
+       { 0x0022, 0x0022, LBP_QU },
+       { 0x0023, 0x0023, LBP_AL },
+       { 0x0024, 0x0024, LBP_PR },
+       { 0x0025, 0x0025, LBP_PO },
+       { 0x0026, 0x0026, LBP_AL },
+       { 0x0027, 0x0027, LBP_QU },
+       { 0x0028, 0x0028, LBP_OP },
+       { 0x0029, 0x0029, LBP_CP },
+       { 0x002A, 0x002A, LBP_AL },
+       { 0x002B, 0x002B, LBP_PR },
+       { 0x002C, 0x002C, LBP_IS },
+       { 0x002D, 0x002D, LBP_HY },
+       { 0x002E, 0x002E, LBP_IS },
+       { 0x002F, 0x002F, LBP_SY },
+       { 0x0030, 0x0039, LBP_NU },
+       { 0x003A, 0x003B, LBP_IS },
+       { 0x003C, 0x003E, LBP_AL },
+       { 0x003F, 0x003F, LBP_EX },
+       { 0x0040, 0x005A, LBP_AL },
+       { 0x005B, 0x005B, LBP_OP },
+       { 0x005C, 0x005C, LBP_PR },
+       { 0x005D, 0x005D, LBP_CP },
+       { 0x005E, 0x007A, LBP_AL },
+       { 0x007B, 0x007B, LBP_OP },
+       { 0x007C, 0x007C, LBP_BA },
+       { 0x007D, 0x007D, LBP_CL },
+       { 0x007E, 0x007E, LBP_AL },
+       { 0x007F, 0x0084, LBP_CM },
+       { 0x0085, 0x0085, LBP_NL },
+       { 0x0086, 0x009F, LBP_CM },
+       { 0x00A0, 0x00A0, LBP_GL },
+       { 0x00A1, 0x00A1, LBP_OP },
+       { 0x00A2, 0x00A2, LBP_PO },
+       { 0x00A3, 0x00A5, LBP_PR },
+       { 0x00A6, 0x00A6, LBP_AL },
+       { 0x00A7, 0x00A8, LBP_AI },
+       { 0x00A9, 0x00A9, LBP_AL },
+       { 0x00AA, 0x00AA, LBP_AI },
+       { 0x00AB, 0x00AB, LBP_QU },
+       { 0x00AC, 0x00AC, LBP_AL },
+       { 0x00AD, 0x00AD, LBP_BA },
+       { 0x00AE, 0x00AF, LBP_AL },
+       { 0x00B0, 0x00B0, LBP_PO },
+       { 0x00B1, 0x00B1, LBP_PR },
+       { 0x00B2, 0x00B3, LBP_AI },
+       { 0x00B4, 0x00B4, LBP_BB },
+       { 0x00B5, 0x00B5, LBP_AL },
+       { 0x00B6, 0x00BA, LBP_AI },
+       { 0x00BB, 0x00BB, LBP_QU },
+       { 0x00BC, 0x00BE, LBP_AI },
+       { 0x00BF, 0x00BF, LBP_OP },
+       { 0x00C0, 0x00D6, LBP_AL },
+       { 0x00D7, 0x00D7, LBP_AI },
+       { 0x00D8, 0x00F6, LBP_AL },
+       { 0x00F7, 0x00F7, LBP_AI },
+       { 0x00F8, 0x02C6, LBP_AL },
+       { 0x02C7, 0x02C7, LBP_AI },
+       { 0x02C8, 0x02C8, LBP_BB },
+       { 0x02C9, 0x02CB, LBP_AI },
+       { 0x02CC, 0x02CC, LBP_BB },
+       { 0x02CD, 0x02CD, LBP_AI },
+       { 0x02CE, 0x02CF, LBP_AL },
+       { 0x02D0, 0x02D0, LBP_AI },
+       { 0x02D1, 0x02D7, LBP_AL },
+       { 0x02D8, 0x02DB, LBP_AI },
+       { 0x02DC, 0x02DC, LBP_AL },
+       { 0x02DD, 0x02DD, LBP_AI },
+       { 0x02DE, 0x02DE, LBP_AL },
+       { 0x02DF, 0x02DF, LBP_BB },
+       { 0x02E0, 0x02FF, LBP_AL },
+       { 0x0300, 0x034E, LBP_CM },
+       { 0x034F, 0x034F, LBP_GL },
+       { 0x0350, 0x035B, LBP_CM },
+       { 0x035C, 0x0362, LBP_GL },
+       { 0x0363, 0x036F, LBP_CM },
+       { 0x0370, 0x037D, LBP_AL },
+       { 0x037E, 0x037E, LBP_IS },
+       { 0x037F, 0x0482, LBP_AL },
+       { 0x0483, 0x0489, LBP_CM },
+       { 0x048A, 0x0587, LBP_AL },
+       { 0x0589, 0x0589, LBP_IS },
+       { 0x058A, 0x058A, LBP_BA },
+       { 0x058D, 0x058E, LBP_AL },
+       { 0x058F, 0x058F, LBP_PR },
+       { 0x0591, 0x05BD, LBP_CM },
+       { 0x05BE, 0x05BE, LBP_BA },
+       { 0x05BF, 0x05BF, LBP_CM },
+       { 0x05C0, 0x05C0, LBP_AL },
+       { 0x05C1, 0x05C2, LBP_CM },
+       { 0x05C3, 0x05C3, LBP_AL },
+       { 0x05C4, 0x05C5, LBP_CM },
+       { 0x05C6, 0x05C6, LBP_EX },
+       { 0x05C7, 0x05C7, LBP_CM },
+       { 0x05D0, 0x05F2, LBP_HL },
+       { 0x05F3, 0x0608, LBP_AL },
+       { 0x0609, 0x060B, LBP_PO },
+       { 0x060C, 0x060D, LBP_IS },
+       { 0x060E, 0x060F, LBP_AL },
+       { 0x0610, 0x061A, LBP_CM },
+       { 0x061B, 0x061B, LBP_EX },
+       { 0x061C, 0x061C, LBP_CM },
+       { 0x061E, 0x061F, LBP_EX },
+       { 0x0620, 0x064A, LBP_AL },
+       { 0x064B, 0x065F, LBP_CM },
+       { 0x0660, 0x0669, LBP_NU },
+       { 0x066A, 0x066A, LBP_PO },
+       { 0x066B, 0x066C, LBP_NU },
+       { 0x066D, 0x066F, LBP_AL },
+       { 0x0670, 0x0670, LBP_CM },
+       { 0x0671, 0x06D3, LBP_AL },
+       { 0x06D4, 0x06D4, LBP_EX },
+       { 0x06D5, 0x06D5, LBP_AL },
+       { 0x06D6, 0x06DC, LBP_CM },
+       { 0x06DD, 0x06DE, LBP_AL },
+       { 0x06DF, 0x06E4, LBP_CM },
+       { 0x06E5, 0x06E6, LBP_AL },
+       { 0x06E7, 0x06E8, LBP_CM },
+       { 0x06E9, 0x06E9, LBP_AL },
+       { 0x06EA, 0x06ED, LBP_CM },
+       { 0x06EE, 0x06EF, LBP_AL },
+       { 0x06F0, 0x06F9, LBP_NU },
+       { 0x06FA, 0x0710, LBP_AL },
+       { 0x0711, 0x0711, LBP_CM },
+       { 0x0712, 0x072F, LBP_AL },
+       { 0x0730, 0x074A, LBP_CM },
+       { 0x074D, 0x07A5, LBP_AL },
+       { 0x07A6, 0x07B0, LBP_CM },
+       { 0x07B1, 0x07B1, LBP_AL },
+       { 0x07C0, 0x07C9, LBP_NU },
+       { 0x07CA, 0x07EA, LBP_AL },
+       { 0x07EB, 0x07F3, LBP_CM },
+       { 0x07F4, 0x07F7, LBP_AL },
+       { 0x07F8, 0x07F8, LBP_IS },
+       { 0x07F9, 0x07F9, LBP_EX },
+       { 0x07FA, 0x0815, LBP_AL },
+       { 0x0816, 0x0819, LBP_CM },
+       { 0x081A, 0x081A, LBP_AL },
+       { 0x081B, 0x0823, LBP_CM },
+       { 0x0824, 0x0824, LBP_AL },
+       { 0x0825, 0x0827, LBP_CM },
+       { 0x0828, 0x0828, LBP_AL },
+       { 0x0829, 0x082D, LBP_CM },
+       { 0x0830, 0x0858, LBP_AL },
+       { 0x0859, 0x085B, LBP_CM },
+       { 0x085E, 0x08B2, LBP_AL },
+       { 0x08E4, 0x0903, LBP_CM },
+       { 0x0904, 0x0939, LBP_AL },
+       { 0x093A, 0x093C, LBP_CM },
+       { 0x093D, 0x093D, LBP_AL },
+       { 0x093E, 0x094F, LBP_CM },
+       { 0x0950, 0x0950, LBP_AL },
+       { 0x0951, 0x0957, LBP_CM },
+       { 0x0958, 0x0961, LBP_AL },
+       { 0x0962, 0x0963, LBP_CM },
+       { 0x0964, 0x0965, LBP_BA },
+       { 0x0966, 0x096F, LBP_NU },
+       { 0x0970, 0x0980, LBP_AL },
+       { 0x0981, 0x0983, LBP_CM },
+       { 0x0985, 0x09B9, LBP_AL },
+       { 0x09BC, 0x09BC, LBP_CM },
+       { 0x09BD, 0x09BD, LBP_AL },
+       { 0x09BE, 0x09CD, LBP_CM },
+       { 0x09CE, 0x09CE, LBP_AL },
+       { 0x09D7, 0x09D7, LBP_CM },
+       { 0x09DC, 0x09E1, LBP_AL },
+       { 0x09E2, 0x09E3, LBP_CM },
+       { 0x09E6, 0x09EF, LBP_NU },
+       { 0x09F0, 0x09F1, LBP_AL },
+       { 0x09F2, 0x09F3, LBP_PO },
+       { 0x09F4, 0x09F8, LBP_AL },
+       { 0x09F9, 0x09F9, LBP_PO },
+       { 0x09FA, 0x09FA, LBP_AL },
+       { 0x09FB, 0x09FB, LBP_PR },
+       { 0x0A01, 0x0A03, LBP_CM },
+       { 0x0A05, 0x0A39, LBP_AL },
+       { 0x0A3C, 0x0A51, LBP_CM },
+       { 0x0A59, 0x0A5E, LBP_AL },
+       { 0x0A66, 0x0A6F, LBP_NU },
+       { 0x0A70, 0x0A71, LBP_CM },
+       { 0x0A72, 0x0A74, LBP_AL },
+       { 0x0A75, 0x0A83, LBP_CM },
+       { 0x0A85, 0x0AB9, LBP_AL },
+       { 0x0ABC, 0x0ABC, LBP_CM },
+       { 0x0ABD, 0x0ABD, LBP_AL },
+       { 0x0ABE, 0x0ACD, LBP_CM },
+       { 0x0AD0, 0x0AE1, LBP_AL },
+       { 0x0AE2, 0x0AE3, LBP_CM },
+       { 0x0AE6, 0x0AEF, LBP_NU },
+       { 0x0AF0, 0x0AF0, LBP_AL },
+       { 0x0AF1, 0x0AF1, LBP_PR },
+       { 0x0B01, 0x0B03, LBP_CM },
+       { 0x0B05, 0x0B39, LBP_AL },
+       { 0x0B3C, 0x0B3C, LBP_CM },
+       { 0x0B3D, 0x0B3D, LBP_AL },
+       { 0x0B3E, 0x0B57, LBP_CM },
+       { 0x0B5C, 0x0B61, LBP_AL },
+       { 0x0B62, 0x0B63, LBP_CM },
+       { 0x0B66, 0x0B6F, LBP_NU },
+       { 0x0B70, 0x0B77, LBP_AL },
+       { 0x0B82, 0x0B82, LBP_CM },
+       { 0x0B83, 0x0BB9, LBP_AL },
+       { 0x0BBE, 0x0BCD, LBP_CM },
+       { 0x0BD0, 0x0BD0, LBP_AL },
+       { 0x0BD7, 0x0BD7, LBP_CM },
+       { 0x0BE6, 0x0BEF, LBP_NU },
+       { 0x0BF0, 0x0BF8, LBP_AL },
+       { 0x0BF9, 0x0BF9, LBP_PR },
+       { 0x0BFA, 0x0BFA, LBP_AL },
+       { 0x0C00, 0x0C03, LBP_CM },
+       { 0x0C05, 0x0C3D, LBP_AL },
+       { 0x0C3E, 0x0C56, LBP_CM },
+       { 0x0C58, 0x0C61, LBP_AL },
+       { 0x0C62, 0x0C63, LBP_CM },
+       { 0x0C66, 0x0C6F, LBP_NU },
+       { 0x0C78, 0x0C7F, LBP_AL },
+       { 0x0C81, 0x0C83, LBP_CM },
+       { 0x0C85, 0x0CB9, LBP_AL },
+       { 0x0CBC, 0x0CBC, LBP_CM },
+       { 0x0CBD, 0x0CBD, LBP_AL },
+       { 0x0CBE, 0x0CD6, LBP_CM },
+       { 0x0CDE, 0x0CE1, LBP_AL },
+       { 0x0CE2, 0x0CE3, LBP_CM },
+       { 0x0CE6, 0x0CEF, LBP_NU },
+       { 0x0CF1, 0x0CF2, LBP_AL },
+       { 0x0D01, 0x0D03, LBP_CM },
+       { 0x0D05, 0x0D3D, LBP_AL },
+       { 0x0D3E, 0x0D4D, LBP_CM },
+       { 0x0D4E, 0x0D4E, LBP_AL },
+       { 0x0D57, 0x0D57, LBP_CM },
+       { 0x0D60, 0x0D61, LBP_AL },
+       { 0x0D62, 0x0D63, LBP_CM },
+       { 0x0D66, 0x0D6F, LBP_NU },
+       { 0x0D70, 0x0D75, LBP_AL },
+       { 0x0D79, 0x0D79, LBP_PO },
+       { 0x0D7A, 0x0D7F, LBP_AL },
+       { 0x0D82, 0x0D83, LBP_CM },
+       { 0x0D85, 0x0DC6, LBP_AL },
+       { 0x0DCA, 0x0DDF, LBP_CM },
+       { 0x0DE6, 0x0DEF, LBP_NU },
+       { 0x0DF2, 0x0DF3, LBP_CM },
+       { 0x0DF4, 0x0DF4, LBP_AL },
+       { 0x0E01, 0x0E3A, LBP_SA },
+       { 0x0E3F, 0x0E3F, LBP_PR },
+       { 0x0E40, 0x0E4E, LBP_SA },
+       { 0x0E4F, 0x0E4F, LBP_AL },
+       { 0x0E50, 0x0E59, LBP_NU },
+       { 0x0E5A, 0x0E5B, LBP_BA },
+       { 0x0E81, 0x0ECD, LBP_SA },
+       { 0x0ED0, 0x0ED9, LBP_NU },
+       { 0x0EDC, 0x0EDF, LBP_SA },
+       { 0x0F00, 0x0F00, LBP_AL },
+       { 0x0F01, 0x0F04, LBP_BB },
+       { 0x0F05, 0x0F05, LBP_AL },
+       { 0x0F06, 0x0F07, LBP_BB },
+       { 0x0F08, 0x0F08, LBP_GL },
+       { 0x0F09, 0x0F0A, LBP_BB },
+       { 0x0F0B, 0x0F0B, LBP_BA },
+       { 0x0F0C, 0x0F0C, LBP_GL },
+       { 0x0F0D, 0x0F11, LBP_EX },
+       { 0x0F12, 0x0F12, LBP_GL },
+       { 0x0F13, 0x0F13, LBP_AL },
+       { 0x0F14, 0x0F14, LBP_EX },
+       { 0x0F15, 0x0F17, LBP_AL },
+       { 0x0F18, 0x0F19, LBP_CM },
+       { 0x0F1A, 0x0F1F, LBP_AL },
+       { 0x0F20, 0x0F29, LBP_NU },
+       { 0x0F2A, 0x0F33, LBP_AL },
+       { 0x0F34, 0x0F34, LBP_BA },
+       { 0x0F35, 0x0F35, LBP_CM },
+       { 0x0F36, 0x0F36, LBP_AL },
+       { 0x0F37, 0x0F37, LBP_CM },
+       { 0x0F38, 0x0F38, LBP_AL },
+       { 0x0F39, 0x0F39, LBP_CM },
+       { 0x0F3A, 0x0F3A, LBP_OP },
+       { 0x0F3B, 0x0F3B, LBP_CL },
+       { 0x0F3C, 0x0F3C, LBP_OP },
+       { 0x0F3D, 0x0F3D, LBP_CL },
+       { 0x0F3E, 0x0F3F, LBP_CM },
+       { 0x0F40, 0x0F6C, LBP_AL },
+       { 0x0F71, 0x0F7E, LBP_CM },
+       { 0x0F7F, 0x0F7F, LBP_BA },
+       { 0x0F80, 0x0F84, LBP_CM },
+       { 0x0F85, 0x0F85, LBP_BA },
+       { 0x0F86, 0x0F87, LBP_CM },
+       { 0x0F88, 0x0F8C, LBP_AL },
+       { 0x0F8D, 0x0FBC, LBP_CM },
+       { 0x0FBE, 0x0FBF, LBP_BA },
+       { 0x0FC0, 0x0FC5, LBP_AL },
+       { 0x0FC6, 0x0FC6, LBP_CM },
+       { 0x0FC7, 0x0FCF, LBP_AL },
+       { 0x0FD0, 0x0FD1, LBP_BB },
+       { 0x0FD2, 0x0FD2, LBP_BA },
+       { 0x0FD3, 0x0FD3, LBP_BB },
+       { 0x0FD4, 0x0FD8, LBP_AL },
+       { 0x0FD9, 0x0FDA, LBP_GL },
+       { 0x1000, 0x103F, LBP_SA },
+       { 0x1040, 0x1049, LBP_NU },
+       { 0x104A, 0x104B, LBP_BA },
+       { 0x104C, 0x104F, LBP_AL },
+       { 0x1050, 0x108F, LBP_SA },
+       { 0x1090, 0x1099, LBP_NU },
+       { 0x109A, 0x109F, LBP_SA },
+       { 0x10A0, 0x10FF, LBP_AL },
+       { 0x1100, 0x115F, LBP_JL },
+       { 0x1160, 0x11A7, LBP_JV },
+       { 0x11A8, 0x11FF, LBP_JT },
+       { 0x1200, 0x135A, LBP_AL },
+       { 0x135D, 0x135F, LBP_CM },
+       { 0x1360, 0x1360, LBP_AL },
+       { 0x1361, 0x1361, LBP_BA },
+       { 0x1362, 0x13F4, LBP_AL },
+       { 0x1400, 0x1400, LBP_BA },
+       { 0x1401, 0x167F, LBP_AL },
+       { 0x1680, 0x1680, LBP_BA },
+       { 0x1681, 0x169A, LBP_AL },
+       { 0x169B, 0x169B, LBP_OP },
+       { 0x169C, 0x169C, LBP_CL },
+       { 0x16A0, 0x16EA, LBP_AL },
+       { 0x16EB, 0x16ED, LBP_BA },
+       { 0x16EE, 0x1711, LBP_AL },
+       { 0x1712, 0x1714, LBP_CM },
+       { 0x1720, 0x1731, LBP_AL },
+       { 0x1732, 0x1734, LBP_CM },
+       { 0x1735, 0x1736, LBP_BA },
+       { 0x1740, 0x1751, LBP_AL },
+       { 0x1752, 0x1753, LBP_CM },
+       { 0x1760, 0x1770, LBP_AL },
+       { 0x1772, 0x1773, LBP_CM },
+       { 0x1780, 0x17D3, LBP_SA },
+       { 0x17D4, 0x17D5, LBP_BA },
+       { 0x17D6, 0x17D6, LBP_NS },
+       { 0x17D7, 0x17D7, LBP_SA },
+       { 0x17D8, 0x17D8, LBP_BA },
+       { 0x17D9, 0x17D9, LBP_AL },
+       { 0x17DA, 0x17DA, LBP_BA },
+       { 0x17DB, 0x17DB, LBP_PR },
+       { 0x17DC, 0x17DD, LBP_SA },
+       { 0x17E0, 0x17E9, LBP_NU },
+       { 0x17F0, 0x1801, LBP_AL },
+       { 0x1802, 0x1803, LBP_EX },
+       { 0x1804, 0x1805, LBP_BA },
+       { 0x1806, 0x1806, LBP_BB },
+       { 0x1807, 0x1807, LBP_AL },
+       { 0x1808, 0x1809, LBP_EX },
+       { 0x180A, 0x180A, LBP_AL },
+       { 0x180B, 0x180D, LBP_CM },
+       { 0x180E, 0x180E, LBP_GL },
+       { 0x1810, 0x1819, LBP_NU },
+       { 0x1820, 0x18A8, LBP_AL },
+       { 0x18A9, 0x18A9, LBP_CM },
+       { 0x18AA, 0x191E, LBP_AL },
+       { 0x1920, 0x193B, LBP_CM },
+       { 0x1940, 0x1940, LBP_AL },
+       { 0x1944, 0x1945, LBP_EX },
+       { 0x1946, 0x194F, LBP_NU },
+       { 0x1950, 0x19C9, LBP_SA },
+       { 0x19D0, 0x19D9, LBP_NU },
+       { 0x19DA, 0x19DF, LBP_SA },
+       { 0x19E0, 0x1A16, LBP_AL },
+       { 0x1A17, 0x1A1B, LBP_CM },
+       { 0x1A1E, 0x1A1F, LBP_AL },
+       { 0x1A20, 0x1A7C, LBP_SA },
+       { 0x1A7F, 0x1A7F, LBP_CM },
+       { 0x1A80, 0x1A99, LBP_NU },
+       { 0x1AA0, 0x1AAD, LBP_SA },
+       { 0x1AB0, 0x1B04, LBP_CM },
+       { 0x1B05, 0x1B33, LBP_AL },
+       { 0x1B34, 0x1B44, LBP_CM },
+       { 0x1B45, 0x1B4B, LBP_AL },
+       { 0x1B50, 0x1B59, LBP_NU },
+       { 0x1B5A, 0x1B5B, LBP_BA },
+       { 0x1B5C, 0x1B5C, LBP_AL },
+       { 0x1B5D, 0x1B60, LBP_BA },
+       { 0x1B61, 0x1B6A, LBP_AL },
+       { 0x1B6B, 0x1B73, LBP_CM },
+       { 0x1B74, 0x1B7C, LBP_AL },
+       { 0x1B80, 0x1B82, LBP_CM },
+       { 0x1B83, 0x1BA0, LBP_AL },
+       { 0x1BA1, 0x1BAD, LBP_CM },
+       { 0x1BAE, 0x1BAF, LBP_AL },
+       { 0x1BB0, 0x1BB9, LBP_NU },
+       { 0x1BBA, 0x1BE5, LBP_AL },
+       { 0x1BE6, 0x1BF3, LBP_CM },
+       { 0x1BFC, 0x1C23, LBP_AL },
+       { 0x1C24, 0x1C37, LBP_CM },
+       { 0x1C3B, 0x1C3F, LBP_BA },
+       { 0x1C40, 0x1C49, LBP_NU },
+       { 0x1C4D, 0x1C4F, LBP_AL },
+       { 0x1C50, 0x1C59, LBP_NU },
+       { 0x1C5A, 0x1C7D, LBP_AL },
+       { 0x1C7E, 0x1C7F, LBP_BA },
+       { 0x1CC0, 0x1CC7, LBP_AL },
+       { 0x1CD0, 0x1CD2, LBP_CM },
+       { 0x1CD3, 0x1CD3, LBP_AL },
+       { 0x1CD4, 0x1CE8, LBP_CM },
+       { 0x1CE9, 0x1CEC, LBP_AL },
+       { 0x1CED, 0x1CED, LBP_CM },
+       { 0x1CEE, 0x1CF1, LBP_AL },
+       { 0x1CF2, 0x1CF4, LBP_CM },
+       { 0x1CF5, 0x1CF6, LBP_AL },
+       { 0x1CF8, 0x1CF9, LBP_CM },
+       { 0x1D00, 0x1DBF, LBP_AL },
+       { 0x1DC0, 0x1DFF, LBP_CM },
+       { 0x1E00, 0x1FFC, LBP_AL },
+       { 0x1FFD, 0x1FFD, LBP_BB },
+       { 0x1FFE, 0x1FFE, LBP_AL },
+       { 0x2000, 0x2006, LBP_BA },
+       { 0x2007, 0x2007, LBP_GL },
+       { 0x2008, 0x200A, LBP_BA },
+       { 0x200B, 0x200B, LBP_ZW },
+       { 0x200C, 0x200F, LBP_CM },
+       { 0x2010, 0x2010, LBP_BA },
+       { 0x2011, 0x2011, LBP_GL },
+       { 0x2012, 0x2013, LBP_BA },
+       { 0x2014, 0x2014, LBP_B2 },
+       { 0x2015, 0x2016, LBP_AI },
+       { 0x2017, 0x2017, LBP_AL },
+       { 0x2018, 0x2019, LBP_QU },
+       { 0x201A, 0x201A, LBP_OP },
+       { 0x201B, 0x201D, LBP_QU },
+       { 0x201E, 0x201E, LBP_OP },
+       { 0x201F, 0x201F, LBP_QU },
+       { 0x2020, 0x2021, LBP_AI },
+       { 0x2022, 0x2023, LBP_AL },
+       { 0x2024, 0x2026, LBP_IN },
+       { 0x2027, 0x2027, LBP_BA },
+       { 0x2028, 0x2029, LBP_BK },
+       { 0x202A, 0x202E, LBP_CM },
+       { 0x202F, 0x202F, LBP_GL },
+       { 0x2030, 0x2037, LBP_PO },
+       { 0x2038, 0x2038, LBP_AL },
+       { 0x2039, 0x203A, LBP_QU },
+       { 0x203B, 0x203B, LBP_AI },
+       { 0x203C, 0x203D, LBP_NS },
+       { 0x203E, 0x2043, LBP_AL },
+       { 0x2044, 0x2044, LBP_IS },
+       { 0x2045, 0x2045, LBP_OP },
+       { 0x2046, 0x2046, LBP_CL },
+       { 0x2047, 0x2049, LBP_NS },
+       { 0x204A, 0x2055, LBP_AL },
+       { 0x2056, 0x2056, LBP_BA },
+       { 0x2057, 0x2057, LBP_AL },
+       { 0x2058, 0x205B, LBP_BA },
+       { 0x205C, 0x205C, LBP_AL },
+       { 0x205D, 0x205F, LBP_BA },
+       { 0x2060, 0x2060, LBP_WJ },
+       { 0x2061, 0x2064, LBP_AL },
+       { 0x2066, 0x206F, LBP_CM },
+       { 0x2070, 0x2071, LBP_AL },
+       { 0x2074, 0x2074, LBP_AI },
+       { 0x2075, 0x207C, LBP_AL },
+       { 0x207D, 0x207D, LBP_OP },
+       { 0x207E, 0x207E, LBP_CL },
+       { 0x207F, 0x207F, LBP_AI },
+       { 0x2080, 0x2080, LBP_AL },
+       { 0x2081, 0x2084, LBP_AI },
+       { 0x2085, 0x208C, LBP_AL },
+       { 0x208D, 0x208D, LBP_OP },
+       { 0x208E, 0x208E, LBP_CL },
+       { 0x2090, 0x209C, LBP_AL },
+       { 0x20A0, 0x20A6, LBP_PR },
+       { 0x20A7, 0x20A7, LBP_PO },
+       { 0x20A8, 0x20B5, LBP_PR },
+       { 0x20B6, 0x20B6, LBP_PO },
+       { 0x20B7, 0x20BA, LBP_PR },
+       { 0x20BB, 0x20BB, LBP_PO },
+       { 0x20BC, 0x20CF, LBP_PR },
+       { 0x20D0, 0x20F0, LBP_CM },
+       { 0x2100, 0x2102, LBP_AL },
+       { 0x2103, 0x2103, LBP_PO },
+       { 0x2104, 0x2104, LBP_AL },
+       { 0x2105, 0x2105, LBP_AI },
+       { 0x2106, 0x2108, LBP_AL },
+       { 0x2109, 0x2109, LBP_PO },
+       { 0x210A, 0x2112, LBP_AL },
+       { 0x2113, 0x2113, LBP_AI },
+       { 0x2114, 0x2115, LBP_AL },
+       { 0x2116, 0x2116, LBP_PR },
+       { 0x2117, 0x2120, LBP_AL },
+       { 0x2121, 0x2122, LBP_AI },
+       { 0x2123, 0x212A, LBP_AL },
+       { 0x212B, 0x212B, LBP_AI },
+       { 0x212C, 0x2153, LBP_AL },
+       { 0x2154, 0x2155, LBP_AI },
+       { 0x2156, 0x215A, LBP_AL },
+       { 0x215B, 0x215B, LBP_AI },
+       { 0x215C, 0x215D, LBP_AL },
+       { 0x215E, 0x215E, LBP_AI },
+       { 0x215F, 0x215F, LBP_AL },
+       { 0x2160, 0x216B, LBP_AI },
+       { 0x216C, 0x216F, LBP_AL },
+       { 0x2170, 0x2179, LBP_AI },
+       { 0x217A, 0x2188, LBP_AL },
+       { 0x2189, 0x2199, LBP_AI },
+       { 0x219A, 0x21D1, LBP_AL },
+       { 0x21D2, 0x21D2, LBP_AI },
+       { 0x21D3, 0x21D3, LBP_AL },
+       { 0x21D4, 0x21D4, LBP_AI },
+       { 0x21D5, 0x21FF, LBP_AL },
+       { 0x2200, 0x2200, LBP_AI },
+       { 0x2201, 0x2201, LBP_AL },
+       { 0x2202, 0x2203, LBP_AI },
+       { 0x2204, 0x2206, LBP_AL },
+       { 0x2207, 0x2208, LBP_AI },
+       { 0x2209, 0x220A, LBP_AL },
+       { 0x220B, 0x220B, LBP_AI },
+       { 0x220C, 0x220E, LBP_AL },
+       { 0x220F, 0x220F, LBP_AI },
+       { 0x2210, 0x2210, LBP_AL },
+       { 0x2211, 0x2211, LBP_AI },
+       { 0x2212, 0x2213, LBP_PR },
+       { 0x2214, 0x2214, LBP_AL },
+       { 0x2215, 0x2215, LBP_AI },
+       { 0x2216, 0x2219, LBP_AL },
+       { 0x221A, 0x221A, LBP_AI },
+       { 0x221B, 0x221C, LBP_AL },
+       { 0x221D, 0x2220, LBP_AI },
+       { 0x2221, 0x2222, LBP_AL },
+       { 0x2223, 0x2223, LBP_AI },
+       { 0x2224, 0x2224, LBP_AL },
+       { 0x2225, 0x2225, LBP_AI },
+       { 0x2226, 0x2226, LBP_AL },
+       { 0x2227, 0x222C, LBP_AI },
+       { 0x222D, 0x222D, LBP_AL },
+       { 0x222E, 0x222E, LBP_AI },
+       { 0x222F, 0x2233, LBP_AL },
+       { 0x2234, 0x2237, LBP_AI },
+       { 0x2238, 0x223B, LBP_AL },
+       { 0x223C, 0x223D, LBP_AI },
+       { 0x223E, 0x2247, LBP_AL },
+       { 0x2248, 0x2248, LBP_AI },
+       { 0x2249, 0x224B, LBP_AL },
+       { 0x224C, 0x224C, LBP_AI },
+       { 0x224D, 0x2251, LBP_AL },
+       { 0x2252, 0x2252, LBP_AI },
+       { 0x2253, 0x225F, LBP_AL },
+       { 0x2260, 0x2261, LBP_AI },
+       { 0x2262, 0x2263, LBP_AL },
+       { 0x2264, 0x2267, LBP_AI },
+       { 0x2268, 0x2269, LBP_AL },
+       { 0x226A, 0x226B, LBP_AI },
+       { 0x226C, 0x226D, LBP_AL },
+       { 0x226E, 0x226F, LBP_AI },
+       { 0x2270, 0x2281, LBP_AL },
+       { 0x2282, 0x2283, LBP_AI },
+       { 0x2284, 0x2285, LBP_AL },
+       { 0x2286, 0x2287, LBP_AI },
+       { 0x2288, 0x2294, LBP_AL },
+       { 0x2295, 0x2295, LBP_AI },
+       { 0x2296, 0x2298, LBP_AL },
+       { 0x2299, 0x2299, LBP_AI },
+       { 0x229A, 0x22A4, LBP_AL },
+       { 0x22A5, 0x22A5, LBP_AI },
+       { 0x22A6, 0x22BE, LBP_AL },
+       { 0x22BF, 0x22BF, LBP_AI },
+       { 0x22C0, 0x2307, LBP_AL },
+       { 0x2308, 0x2308, LBP_OP },
+       { 0x2309, 0x2309, LBP_CL },
+       { 0x230A, 0x230A, LBP_OP },
+       { 0x230B, 0x230B, LBP_CL },
+       { 0x230C, 0x2311, LBP_AL },
+       { 0x2312, 0x2312, LBP_AI },
+       { 0x2313, 0x2319, LBP_AL },
+       { 0x231A, 0x231B, LBP_ID },
+       { 0x231C, 0x2328, LBP_AL },
+       { 0x2329, 0x2329, LBP_OP },
+       { 0x232A, 0x232A, LBP_CL },
+       { 0x232B, 0x23EF, LBP_AL },
+       { 0x23F0, 0x23F3, LBP_ID },
+       { 0x23F4, 0x244A, LBP_AL },
+       { 0x2460, 0x24FE, LBP_AI },
+       { 0x24FF, 0x24FF, LBP_AL },
+       { 0x2500, 0x254B, LBP_AI },
+       { 0x254C, 0x254F, LBP_AL },
+       { 0x2550, 0x2574, LBP_AI },
+       { 0x2575, 0x257F, LBP_AL },
+       { 0x2580, 0x258F, LBP_AI },
+       { 0x2590, 0x2591, LBP_AL },
+       { 0x2592, 0x2595, LBP_AI },
+       { 0x2596, 0x259F, LBP_AL },
+       { 0x25A0, 0x25A1, LBP_AI },
+       { 0x25A2, 0x25A2, LBP_AL },
+       { 0x25A3, 0x25A9, LBP_AI },
+       { 0x25AA, 0x25B1, LBP_AL },
+       { 0x25B2, 0x25B3, LBP_AI },
+       { 0x25B4, 0x25B5, LBP_AL },
+       { 0x25B6, 0x25B7, LBP_AI },
+       { 0x25B8, 0x25BB, LBP_AL },
+       { 0x25BC, 0x25BD, LBP_AI },
+       { 0x25BE, 0x25BF, LBP_AL },
+       { 0x25C0, 0x25C1, LBP_AI },
+       { 0x25C2, 0x25C5, LBP_AL },
+       { 0x25C6, 0x25C8, LBP_AI },
+       { 0x25C9, 0x25CA, LBP_AL },
+       { 0x25CB, 0x25CB, LBP_AI },
+       { 0x25CC, 0x25CD, LBP_AL },
+       { 0x25CE, 0x25D1, LBP_AI },
+       { 0x25D2, 0x25E1, LBP_AL },
+       { 0x25E2, 0x25E5, LBP_AI },
+       { 0x25E6, 0x25EE, LBP_AL },
+       { 0x25EF, 0x25EF, LBP_AI },
+       { 0x25F0, 0x25FF, LBP_AL },
+       { 0x2600, 0x2603, LBP_ID },
+       { 0x2604, 0x2604, LBP_AL },
+       { 0x2605, 0x2606, LBP_AI },
+       { 0x2607, 0x2608, LBP_AL },
+       { 0x2609, 0x2609, LBP_AI },
+       { 0x260A, 0x260D, LBP_AL },
+       { 0x260E, 0x260F, LBP_AI },
+       { 0x2610, 0x2613, LBP_AL },
+       { 0x2614, 0x2615, LBP_ID },
+       { 0x2616, 0x2617, LBP_AI },
+       { 0x2618, 0x2618, LBP_ID },
+       { 0x2619, 0x2619, LBP_AL },
+       { 0x261A, 0x261F, LBP_ID },
+       { 0x2620, 0x2638, LBP_AL },
+       { 0x2639, 0x263B, LBP_ID },
+       { 0x263C, 0x263F, LBP_AL },
+       { 0x2640, 0x2640, LBP_AI },
+       { 0x2641, 0x2641, LBP_AL },
+       { 0x2642, 0x2642, LBP_AI },
+       { 0x2643, 0x265F, LBP_AL },
+       { 0x2660, 0x2661, LBP_AI },
+       { 0x2662, 0x2662, LBP_AL },
+       { 0x2663, 0x2665, LBP_AI },
+       { 0x2666, 0x2666, LBP_AL },
+       { 0x2667, 0x2667, LBP_AI },
+       { 0x2668, 0x2668, LBP_ID },
+       { 0x2669, 0x266A, LBP_AI },
+       { 0x266B, 0x266B, LBP_AL },
+       { 0x266C, 0x266D, LBP_AI },
+       { 0x266E, 0x266E, LBP_AL },
+       { 0x266F, 0x266F, LBP_AI },
+       { 0x2670, 0x267E, LBP_AL },
+       { 0x267F, 0x267F, LBP_ID },
+       { 0x2680, 0x269D, LBP_AL },
+       { 0x269E, 0x269F, LBP_AI },
+       { 0x26A0, 0x26BC, LBP_AL },
+       { 0x26BD, 0x26C8, LBP_ID },
+       { 0x26C9, 0x26CC, LBP_AI },
+       { 0x26CD, 0x26CD, LBP_ID },
+       { 0x26CE, 0x26CE, LBP_AL },
+       { 0x26CF, 0x26D1, LBP_ID },
+       { 0x26D2, 0x26D2, LBP_AI },
+       { 0x26D3, 0x26D4, LBP_ID },
+       { 0x26D5, 0x26D7, LBP_AI },
+       { 0x26D8, 0x26D9, LBP_ID },
+       { 0x26DA, 0x26DB, LBP_AI },
+       { 0x26DC, 0x26DC, LBP_ID },
+       { 0x26DD, 0x26DE, LBP_AI },
+       { 0x26DF, 0x26E1, LBP_ID },
+       { 0x26E2, 0x26E2, LBP_AL },
+       { 0x26E3, 0x26E3, LBP_AI },
+       { 0x26E4, 0x26E7, LBP_AL },
+       { 0x26E8, 0x26E9, LBP_AI },
+       { 0x26EA, 0x26EA, LBP_ID },
+       { 0x26EB, 0x26F0, LBP_AI },
+       { 0x26F1, 0x26F5, LBP_ID },
+       { 0x26F6, 0x26F6, LBP_AI },
+       { 0x26F7, 0x26FA, LBP_ID },
+       { 0x26FB, 0x26FC, LBP_AI },
+       { 0x26FD, 0x2704, LBP_ID },
+       { 0x2705, 0x2707, LBP_AL },
+       { 0x2708, 0x270D, LBP_ID },
+       { 0x270E, 0x2756, LBP_AL },
+       { 0x2757, 0x2757, LBP_AI },
+       { 0x2758, 0x275A, LBP_AL },
+       { 0x275B, 0x2760, LBP_QU },
+       { 0x2761, 0x2761, LBP_AL },
+       { 0x2762, 0x2763, LBP_EX },
+       { 0x2764, 0x2767, LBP_AL },
+       { 0x2768, 0x2768, LBP_OP },
+       { 0x2769, 0x2769, LBP_CL },
+       { 0x276A, 0x276A, LBP_OP },
+       { 0x276B, 0x276B, LBP_CL },
+       { 0x276C, 0x276C, LBP_OP },
+       { 0x276D, 0x276D, LBP_CL },
+       { 0x276E, 0x276E, LBP_OP },
+       { 0x276F, 0x276F, LBP_CL },
+       { 0x2770, 0x2770, LBP_OP },
+       { 0x2771, 0x2771, LBP_CL },
+       { 0x2772, 0x2772, LBP_OP },
+       { 0x2773, 0x2773, LBP_CL },
+       { 0x2774, 0x2774, LBP_OP },
+       { 0x2775, 0x2775, LBP_CL },
+       { 0x2776, 0x2793, LBP_AI },
+       { 0x2794, 0x27C4, LBP_AL },
+       { 0x27C5, 0x27C5, LBP_OP },
+       { 0x27C6, 0x27C6, LBP_CL },
+       { 0x27C7, 0x27E5, LBP_AL },
+       { 0x27E6, 0x27E6, LBP_OP },
+       { 0x27E7, 0x27E7, LBP_CL },
+       { 0x27E8, 0x27E8, LBP_OP },
+       { 0x27E9, 0x27E9, LBP_CL },
+       { 0x27EA, 0x27EA, LBP_OP },
+       { 0x27EB, 0x27EB, LBP_CL },
+       { 0x27EC, 0x27EC, LBP_OP },
+       { 0x27ED, 0x27ED, LBP_CL },
+       { 0x27EE, 0x27EE, LBP_OP },
+       { 0x27EF, 0x27EF, LBP_CL },
+       { 0x27F0, 0x2982, LBP_AL },
+       { 0x2983, 0x2983, LBP_OP },
+       { 0x2984, 0x2984, LBP_CL },
+       { 0x2985, 0x2985, LBP_OP },
+       { 0x2986, 0x2986, LBP_CL },
+       { 0x2987, 0x2987, LBP_OP },
+       { 0x2988, 0x2988, LBP_CL },
+       { 0x2989, 0x2989, LBP_OP },
+       { 0x298A, 0x298A, LBP_CL },
+       { 0x298B, 0x298B, LBP_OP },
+       { 0x298C, 0x298C, LBP_CL },
+       { 0x298D, 0x298D, LBP_OP },
+       { 0x298E, 0x298E, LBP_CL },
+       { 0x298F, 0x298F, LBP_OP },
+       { 0x2990, 0x2990, LBP_CL },
+       { 0x2991, 0x2991, LBP_OP },
+       { 0x2992, 0x2992, LBP_CL },
+       { 0x2993, 0x2993, LBP_OP },
+       { 0x2994, 0x2994, LBP_CL },
+       { 0x2995, 0x2995, LBP_OP },
+       { 0x2996, 0x2996, LBP_CL },
+       { 0x2997, 0x2997, LBP_OP },
+       { 0x2998, 0x2998, LBP_CL },
+       { 0x2999, 0x29D7, LBP_AL },
+       { 0x29D8, 0x29D8, LBP_OP },
+       { 0x29D9, 0x29D9, LBP_CL },
+       { 0x29DA, 0x29DA, LBP_OP },
+       { 0x29DB, 0x29DB, LBP_CL },
+       { 0x29DC, 0x29FB, LBP_AL },
+       { 0x29FC, 0x29FC, LBP_OP },
+       { 0x29FD, 0x29FD, LBP_CL },
+       { 0x29FE, 0x2B54, LBP_AL },
+       { 0x2B55, 0x2B59, LBP_AI },
+       { 0x2B5A, 0x2CEE, LBP_AL },
+       { 0x2CEF, 0x2CF1, LBP_CM },
+       { 0x2CF2, 0x2CF3, LBP_AL },
+       { 0x2CF9, 0x2CF9, LBP_EX },
+       { 0x2CFA, 0x2CFC, LBP_BA },
+       { 0x2CFD, 0x2CFD, LBP_AL },
+       { 0x2CFE, 0x2CFE, LBP_EX },
+       { 0x2CFF, 0x2CFF, LBP_BA },
+       { 0x2D00, 0x2D6F, LBP_AL },
+       { 0x2D70, 0x2D70, LBP_BA },
+       { 0x2D7F, 0x2D7F, LBP_CM },
+       { 0x2D80, 0x2DDE, LBP_AL },
+       { 0x2DE0, 0x2DFF, LBP_CM },
+       { 0x2E00, 0x2E0D, LBP_QU },
+       { 0x2E0E, 0x2E15, LBP_BA },
+       { 0x2E16, 0x2E16, LBP_AL },
+       { 0x2E17, 0x2E17, LBP_BA },
+       { 0x2E18, 0x2E18, LBP_OP },
+       { 0x2E19, 0x2E19, LBP_BA },
+       { 0x2E1A, 0x2E1B, LBP_AL },
+       { 0x2E1C, 0x2E1D, LBP_QU },
+       { 0x2E1E, 0x2E1F, LBP_AL },
+       { 0x2E20, 0x2E21, LBP_QU },
+       { 0x2E22, 0x2E22, LBP_OP },
+       { 0x2E23, 0x2E23, LBP_CL },
+       { 0x2E24, 0x2E24, LBP_OP },
+       { 0x2E25, 0x2E25, LBP_CL },
+       { 0x2E26, 0x2E26, LBP_OP },
+       { 0x2E27, 0x2E27, LBP_CL },
+       { 0x2E28, 0x2E28, LBP_OP },
+       { 0x2E29, 0x2E29, LBP_CL },
+       { 0x2E2A, 0x2E2D, LBP_BA },
+       { 0x2E2E, 0x2E2E, LBP_EX },
+       { 0x2E2F, 0x2E2F, LBP_AL },
+       { 0x2E30, 0x2E31, LBP_BA },
+       { 0x2E32, 0x2E32, LBP_AL },
+       { 0x2E33, 0x2E34, LBP_BA },
+       { 0x2E35, 0x2E39, LBP_AL },
+       { 0x2E3A, 0x2E3B, LBP_B2 },
+       { 0x2E3C, 0x2E3E, LBP_BA },
+       { 0x2E3F, 0x2E3F, LBP_AL },
+       { 0x2E40, 0x2E41, LBP_BA },
+       { 0x2E42, 0x2E42, LBP_OP },
+       { 0x2E80, 0x2FFB, LBP_ID },
+       { 0x3000, 0x3000, LBP_BA },
+       { 0x3001, 0x3002, LBP_CL },
+       { 0x3003, 0x3004, LBP_ID },
+       { 0x3005, 0x3005, LBP_NS },
+       { 0x3006, 0x3007, LBP_ID },
+       { 0x3008, 0x3008, LBP_OP },
+       { 0x3009, 0x3009, LBP_CL },
+       { 0x300A, 0x300A, LBP_OP },
+       { 0x300B, 0x300B, LBP_CL },
+       { 0x300C, 0x300C, LBP_OP },
+       { 0x300D, 0x300D, LBP_CL },
+       { 0x300E, 0x300E, LBP_OP },
+       { 0x300F, 0x300F, LBP_CL },
+       { 0x3010, 0x3010, LBP_OP },
+       { 0x3011, 0x3011, LBP_CL },
+       { 0x3012, 0x3013, LBP_ID },
+       { 0x3014, 0x3014, LBP_OP },
+       { 0x3015, 0x3015, LBP_CL },
+       { 0x3016, 0x3016, LBP_OP },
+       { 0x3017, 0x3017, LBP_CL },
+       { 0x3018, 0x3018, LBP_OP },
+       { 0x3019, 0x3019, LBP_CL },
+       { 0x301A, 0x301A, LBP_OP },
+       { 0x301B, 0x301B, LBP_CL },
+       { 0x301C, 0x301C, LBP_NS },
+       { 0x301D, 0x301D, LBP_OP },
+       { 0x301E, 0x301F, LBP_CL },
+       { 0x3020, 0x3029, LBP_ID },
+       { 0x302A, 0x302F, LBP_CM },
+       { 0x3030, 0x3034, LBP_ID },
+       { 0x3035, 0x3035, LBP_CM },
+       { 0x3036, 0x303A, LBP_ID },
+       { 0x303B, 0x303C, LBP_NS },
+       { 0x303D, 0x303F, LBP_ID },
+       { 0x3041, 0x3041, LBP_CJ },
+       { 0x3042, 0x3042, LBP_ID },
+       { 0x3043, 0x3043, LBP_CJ },
+       { 0x3044, 0x3044, LBP_ID },
+       { 0x3045, 0x3045, LBP_CJ },
+       { 0x3046, 0x3046, LBP_ID },
+       { 0x3047, 0x3047, LBP_CJ },
+       { 0x3048, 0x3048, LBP_ID },
+       { 0x3049, 0x3049, LBP_CJ },
+       { 0x304A, 0x3062, LBP_ID },
+       { 0x3063, 0x3063, LBP_CJ },
+       { 0x3064, 0x3082, LBP_ID },
+       { 0x3083, 0x3083, LBP_CJ },
+       { 0x3084, 0x3084, LBP_ID },
+       { 0x3085, 0x3085, LBP_CJ },
+       { 0x3086, 0x3086, LBP_ID },
+       { 0x3087, 0x3087, LBP_CJ },
+       { 0x3088, 0x308D, LBP_ID },
+       { 0x308E, 0x308E, LBP_CJ },
+       { 0x308F, 0x3094, LBP_ID },
+       { 0x3095, 0x3096, LBP_CJ },
+       { 0x3099, 0x309A, LBP_CM },
+       { 0x309B, 0x309E, LBP_NS },
+       { 0x309F, 0x309F, LBP_ID },
+       { 0x30A0, 0x30A0, LBP_NS },
+       { 0x30A1, 0x30A1, LBP_CJ },
+       { 0x30A2, 0x30A2, LBP_ID },
+       { 0x30A3, 0x30A3, LBP_CJ },
+       { 0x30A4, 0x30A4, LBP_ID },
+       { 0x30A5, 0x30A5, LBP_CJ },
+       { 0x30A6, 0x30A6, LBP_ID },
+       { 0x30A7, 0x30A7, LBP_CJ },
+       { 0x30A8, 0x30A8, LBP_ID },
+       { 0x30A9, 0x30A9, LBP_CJ },
+       { 0x30AA, 0x30C2, LBP_ID },
+       { 0x30C3, 0x30C3, LBP_CJ },
+       { 0x30C4, 0x30E2, LBP_ID },
+       { 0x30E3, 0x30E3, LBP_CJ },
+       { 0x30E4, 0x30E4, LBP_ID },
+       { 0x30E5, 0x30E5, LBP_CJ },
+       { 0x30E6, 0x30E6, LBP_ID },
+       { 0x30E7, 0x30E7, LBP_CJ },
+       { 0x30E8, 0x30ED, LBP_ID },
+       { 0x30EE, 0x30EE, LBP_CJ },
+       { 0x30EF, 0x30F4, LBP_ID },
+       { 0x30F5, 0x30F6, LBP_CJ },
+       { 0x30F7, 0x30FA, LBP_ID },
+       { 0x30FB, 0x30FB, LBP_NS },
+       { 0x30FC, 0x30FC, LBP_CJ },
+       { 0x30FD, 0x30FE, LBP_NS },
+       { 0x30FF, 0x31E3, LBP_ID },
+       { 0x31F0, 0x31FF, LBP_CJ },
+       { 0x3200, 0x3247, LBP_ID },
+       { 0x3248, 0x324F, LBP_AI },
+       { 0x3250, 0x4DBF, LBP_ID },
+       { 0x4DC0, 0x4DFF, LBP_AL },
+       { 0x4E00, 0xA014, LBP_ID },
+       { 0xA015, 0xA015, LBP_NS },
+       { 0xA016, 0xA4C6, LBP_ID },
+       { 0xA4D0, 0xA4FD, LBP_AL },
+       { 0xA4FE, 0xA4FF, LBP_BA },
+       { 0xA500, 0xA60C, LBP_AL },
+       { 0xA60D, 0xA60D, LBP_BA },
+       { 0xA60E, 0xA60E, LBP_EX },
+       { 0xA60F, 0xA60F, LBP_BA },
+       { 0xA610, 0xA61F, LBP_AL },
+       { 0xA620, 0xA629, LBP_NU },
+       { 0xA62A, 0xA66E, LBP_AL },
+       { 0xA66F, 0xA672, LBP_CM },
+       { 0xA673, 0xA673, LBP_AL },
+       { 0xA674, 0xA67D, LBP_CM },
+       { 0xA67E, 0xA69D, LBP_AL },
+       { 0xA69F, 0xA69F, LBP_CM },
+       { 0xA6A0, 0xA6EF, LBP_AL },
+       { 0xA6F0, 0xA6F1, LBP_CM },
+       { 0xA6F2, 0xA6F2, LBP_AL },
+       { 0xA6F3, 0xA6F7, LBP_BA },
+       { 0xA700, 0xA801, LBP_AL },
+       { 0xA802, 0xA802, LBP_CM },
+       { 0xA803, 0xA805, LBP_AL },
+       { 0xA806, 0xA806, LBP_CM },
+       { 0xA807, 0xA80A, LBP_AL },
+       { 0xA80B, 0xA80B, LBP_CM },
+       { 0xA80C, 0xA822, LBP_AL },
+       { 0xA823, 0xA827, LBP_CM },
+       { 0xA828, 0xA837, LBP_AL },
+       { 0xA838, 0xA838, LBP_PO },
+       { 0xA839, 0xA873, LBP_AL },
+       { 0xA874, 0xA875, LBP_BB },
+       { 0xA876, 0xA877, LBP_EX },
+       { 0xA880, 0xA881, LBP_CM },
+       { 0xA882, 0xA8B3, LBP_AL },
+       { 0xA8B4, 0xA8C4, LBP_CM },
+       { 0xA8CE, 0xA8CF, LBP_BA },
+       { 0xA8D0, 0xA8D9, LBP_NU },
+       { 0xA8E0, 0xA8F1, LBP_CM },
+       { 0xA8F2, 0xA8FB, LBP_AL },
+       { 0xA900, 0xA909, LBP_NU },
+       { 0xA90A, 0xA925, LBP_AL },
+       { 0xA926, 0xA92D, LBP_CM },
+       { 0xA92E, 0xA92F, LBP_BA },
+       { 0xA930, 0xA946, LBP_AL },
+       { 0xA947, 0xA953, LBP_CM },
+       { 0xA95F, 0xA95F, LBP_AL },
+       { 0xA960, 0xA97C, LBP_JL },
+       { 0xA980, 0xA983, LBP_CM },
+       { 0xA984, 0xA9B2, LBP_AL },
+       { 0xA9B3, 0xA9C0, LBP_CM },
+       { 0xA9C1, 0xA9C6, LBP_AL },
+       { 0xA9C7, 0xA9C9, LBP_BA },
+       { 0xA9CA, 0xA9CF, LBP_AL },
+       { 0xA9D0, 0xA9D9, LBP_NU },
+       { 0xA9DE, 0xA9DF, LBP_AL },
+       { 0xA9E0, 0xA9EF, LBP_SA },
+       { 0xA9F0, 0xA9F9, LBP_NU },
+       { 0xA9FA, 0xA9FE, LBP_SA },
+       { 0xAA00, 0xAA28, LBP_AL },
+       { 0xAA29, 0xAA36, LBP_CM },
+       { 0xAA40, 0xAA42, LBP_AL },
+       { 0xAA43, 0xAA43, LBP_CM },
+       { 0xAA44, 0xAA4B, LBP_AL },
+       { 0xAA4C, 0xAA4D, LBP_CM },
+       { 0xAA50, 0xAA59, LBP_NU },
+       { 0xAA5C, 0xAA5C, LBP_AL },
+       { 0xAA5D, 0xAA5F, LBP_BA },
+       { 0xAA60, 0xAADF, LBP_SA },
+       { 0xAAE0, 0xAAEA, LBP_AL },
+       { 0xAAEB, 0xAAEF, LBP_CM },
+       { 0xAAF0, 0xAAF1, LBP_BA },
+       { 0xAAF2, 0xAAF4, LBP_AL },
+       { 0xAAF5, 0xAAF6, LBP_CM },
+       { 0xAB01, 0xABE2, LBP_AL },
+       { 0xABE3, 0xABEA, LBP_CM },
+       { 0xABEB, 0xABEB, LBP_BA },
+       { 0xABEC, 0xABED, LBP_CM },
+       { 0xABF0, 0xABF9, LBP_NU },
+       { 0xAC00, 0xAC00, LBP_H2 },
+       { 0xAC01, 0xAC1B, LBP_H3 },
+       { 0xAC1C, 0xAC1C, LBP_H2 },
+       { 0xAC1D, 0xAC37, LBP_H3 },
+       { 0xAC38, 0xAC38, LBP_H2 },
+       { 0xAC39, 0xAC53, LBP_H3 },
+       { 0xAC54, 0xAC54, LBP_H2 },
+       { 0xAC55, 0xAC6F, LBP_H3 },
+       { 0xAC70, 0xAC70, LBP_H2 },
+       { 0xAC71, 0xAC8B, LBP_H3 },
+       { 0xAC8C, 0xAC8C, LBP_H2 },
+       { 0xAC8D, 0xACA7, LBP_H3 },
+       { 0xACA8, 0xACA8, LBP_H2 },
+       { 0xACA9, 0xACC3, LBP_H3 },
+       { 0xACC4, 0xACC4, LBP_H2 },
+       { 0xACC5, 0xACDF, LBP_H3 },
+       { 0xACE0, 0xACE0, LBP_H2 },
+       { 0xACE1, 0xACFB, LBP_H3 },
+       { 0xACFC, 0xACFC, LBP_H2 },
+       { 0xACFD, 0xAD17, LBP_H3 },
+       { 0xAD18, 0xAD18, LBP_H2 },
+       { 0xAD19, 0xAD33, LBP_H3 },
+       { 0xAD34, 0xAD34, LBP_H2 },
+       { 0xAD35, 0xAD4F, LBP_H3 },
+       { 0xAD50, 0xAD50, LBP_H2 },
+       { 0xAD51, 0xAD6B, LBP_H3 },
+       { 0xAD6C, 0xAD6C, LBP_H2 },
+       { 0xAD6D, 0xAD87, LBP_H3 },
+       { 0xAD88, 0xAD88, LBP_H2 },
+       { 0xAD89, 0xADA3, LBP_H3 },
+       { 0xADA4, 0xADA4, LBP_H2 },
+       { 0xADA5, 0xADBF, LBP_H3 },
+       { 0xADC0, 0xADC0, LBP_H2 },
+       { 0xADC1, 0xADDB, LBP_H3 },
+       { 0xADDC, 0xADDC, LBP_H2 },
+       { 0xADDD, 0xADF7, LBP_H3 },
+       { 0xADF8, 0xADF8, LBP_H2 },
+       { 0xADF9, 0xAE13, LBP_H3 },
+       { 0xAE14, 0xAE14, LBP_H2 },
+       { 0xAE15, 0xAE2F, LBP_H3 },
+       { 0xAE30, 0xAE30, LBP_H2 },
+       { 0xAE31, 0xAE4B, LBP_H3 },
+       { 0xAE4C, 0xAE4C, LBP_H2 },
+       { 0xAE4D, 0xAE67, LBP_H3 },
+       { 0xAE68, 0xAE68, LBP_H2 },
+       { 0xAE69, 0xAE83, LBP_H3 },
+       { 0xAE84, 0xAE84, LBP_H2 },
+       { 0xAE85, 0xAE9F, LBP_H3 },
+       { 0xAEA0, 0xAEA0, LBP_H2 },
+       { 0xAEA1, 0xAEBB, LBP_H3 },
+       { 0xAEBC, 0xAEBC, LBP_H2 },
+       { 0xAEBD, 0xAED7, LBP_H3 },
+       { 0xAED8, 0xAED8, LBP_H2 },
+       { 0xAED9, 0xAEF3, LBP_H3 },
+       { 0xAEF4, 0xAEF4, LBP_H2 },
+       { 0xAEF5, 0xAF0F, LBP_H3 },
+       { 0xAF10, 0xAF10, LBP_H2 },
+       { 0xAF11, 0xAF2B, LBP_H3 },
+       { 0xAF2C, 0xAF2C, LBP_H2 },
+       { 0xAF2D, 0xAF47, LBP_H3 },
+       { 0xAF48, 0xAF48, LBP_H2 },
+       { 0xAF49, 0xAF63, LBP_H3 },
+       { 0xAF64, 0xAF64, LBP_H2 },
+       { 0xAF65, 0xAF7F, LBP_H3 },
+       { 0xAF80, 0xAF80, LBP_H2 },
+       { 0xAF81, 0xAF9B, LBP_H3 },
+       { 0xAF9C, 0xAF9C, LBP_H2 },
+       { 0xAF9D, 0xAFB7, LBP_H3 },
+       { 0xAFB8, 0xAFB8, LBP_H2 },
+       { 0xAFB9, 0xAFD3, LBP_H3 },
+       { 0xAFD4, 0xAFD4, LBP_H2 },
+       { 0xAFD5, 0xAFEF, LBP_H3 },
+       { 0xAFF0, 0xAFF0, LBP_H2 },
+       { 0xAFF1, 0xB00B, LBP_H3 },
+       { 0xB00C, 0xB00C, LBP_H2 },
+       { 0xB00D, 0xB027, LBP_H3 },
+       { 0xB028, 0xB028, LBP_H2 },
+       { 0xB029, 0xB043, LBP_H3 },
+       { 0xB044, 0xB044, LBP_H2 },
+       { 0xB045, 0xB05F, LBP_H3 },
+       { 0xB060, 0xB060, LBP_H2 },
+       { 0xB061, 0xB07B, LBP_H3 },
+       { 0xB07C, 0xB07C, LBP_H2 },
+       { 0xB07D, 0xB097, LBP_H3 },
+       { 0xB098, 0xB098, LBP_H2 },
+       { 0xB099, 0xB0B3, LBP_H3 },
+       { 0xB0B4, 0xB0B4, LBP_H2 },
+       { 0xB0B5, 0xB0CF, LBP_H3 },
+       { 0xB0D0, 0xB0D0, LBP_H2 },
+       { 0xB0D1, 0xB0EB, LBP_H3 },
+       { 0xB0EC, 0xB0EC, LBP_H2 },
+       { 0xB0ED, 0xB107, LBP_H3 },
+       { 0xB108, 0xB108, LBP_H2 },
+       { 0xB109, 0xB123, LBP_H3 },
+       { 0xB124, 0xB124, LBP_H2 },
+       { 0xB125, 0xB13F, LBP_H3 },
+       { 0xB140, 0xB140, LBP_H2 },
+       { 0xB141, 0xB15B, LBP_H3 },
+       { 0xB15C, 0xB15C, LBP_H2 },
+       { 0xB15D, 0xB177, LBP_H3 },
+       { 0xB178, 0xB178, LBP_H2 },
+       { 0xB179, 0xB193, LBP_H3 },
+       { 0xB194, 0xB194, LBP_H2 },
+       { 0xB195, 0xB1AF, LBP_H3 },
+       { 0xB1B0, 0xB1B0, LBP_H2 },
+       { 0xB1B1, 0xB1CB, LBP_H3 },
+       { 0xB1CC, 0xB1CC, LBP_H2 },
+       { 0xB1CD, 0xB1E7, LBP_H3 },
+       { 0xB1E8, 0xB1E8, LBP_H2 },
+       { 0xB1E9, 0xB203, LBP_H3 },
+       { 0xB204, 0xB204, LBP_H2 },
+       { 0xB205, 0xB21F, LBP_H3 },
+       { 0xB220, 0xB220, LBP_H2 },
+       { 0xB221, 0xB23B, LBP_H3 },
+       { 0xB23C, 0xB23C, LBP_H2 },
+       { 0xB23D, 0xB257, LBP_H3 },
+       { 0xB258, 0xB258, LBP_H2 },
+       { 0xB259, 0xB273, LBP_H3 },
+       { 0xB274, 0xB274, LBP_H2 },
+       { 0xB275, 0xB28F, LBP_H3 },
+       { 0xB290, 0xB290, LBP_H2 },
+       { 0xB291, 0xB2AB, LBP_H3 },
+       { 0xB2AC, 0xB2AC, LBP_H2 },
+       { 0xB2AD, 0xB2C7, LBP_H3 },
+       { 0xB2C8, 0xB2C8, LBP_H2 },
+       { 0xB2C9, 0xB2E3, LBP_H3 },
+       { 0xB2E4, 0xB2E4, LBP_H2 },
+       { 0xB2E5, 0xB2FF, LBP_H3 },
+       { 0xB300, 0xB300, LBP_H2 },
+       { 0xB301, 0xB31B, LBP_H3 },
+       { 0xB31C, 0xB31C, LBP_H2 },
+       { 0xB31D, 0xB337, LBP_H3 },
+       { 0xB338, 0xB338, LBP_H2 },
+       { 0xB339, 0xB353, LBP_H3 },
+       { 0xB354, 0xB354, LBP_H2 },
+       { 0xB355, 0xB36F, LBP_H3 },
+       { 0xB370, 0xB370, LBP_H2 },
+       { 0xB371, 0xB38B, LBP_H3 },
+       { 0xB38C, 0xB38C, LBP_H2 },
+       { 0xB38D, 0xB3A7, LBP_H3 },
+       { 0xB3A8, 0xB3A8, LBP_H2 },
+       { 0xB3A9, 0xB3C3, LBP_H3 },
+       { 0xB3C4, 0xB3C4, LBP_H2 },
+       { 0xB3C5, 0xB3DF, LBP_H3 },
+       { 0xB3E0, 0xB3E0, LBP_H2 },
+       { 0xB3E1, 0xB3FB, LBP_H3 },
+       { 0xB3FC, 0xB3FC, LBP_H2 },
+       { 0xB3FD, 0xB417, LBP_H3 },
+       { 0xB418, 0xB418, LBP_H2 },
+       { 0xB419, 0xB433, LBP_H3 },
+       { 0xB434, 0xB434, LBP_H2 },
+       { 0xB435, 0xB44F, LBP_H3 },
+       { 0xB450, 0xB450, LBP_H2 },
+       { 0xB451, 0xB46B, LBP_H3 },
+       { 0xB46C, 0xB46C, LBP_H2 },
+       { 0xB46D, 0xB487, LBP_H3 },
+       { 0xB488, 0xB488, LBP_H2 },
+       { 0xB489, 0xB4A3, LBP_H3 },
+       { 0xB4A4, 0xB4A4, LBP_H2 },
+       { 0xB4A5, 0xB4BF, LBP_H3 },
+       { 0xB4C0, 0xB4C0, LBP_H2 },
+       { 0xB4C1, 0xB4DB, LBP_H3 },
+       { 0xB4DC, 0xB4DC, LBP_H2 },
+       { 0xB4DD, 0xB4F7, LBP_H3 },
+       { 0xB4F8, 0xB4F8, LBP_H2 },
+       { 0xB4F9, 0xB513, LBP_H3 },
+       { 0xB514, 0xB514, LBP_H2 },
+       { 0xB515, 0xB52F, LBP_H3 },
+       { 0xB530, 0xB530, LBP_H2 },
+       { 0xB531, 0xB54B, LBP_H3 },
+       { 0xB54C, 0xB54C, LBP_H2 },
+       { 0xB54D, 0xB567, LBP_H3 },
+       { 0xB568, 0xB568, LBP_H2 },
+       { 0xB569, 0xB583, LBP_H3 },
+       { 0xB584, 0xB584, LBP_H2 },
+       { 0xB585, 0xB59F, LBP_H3 },
+       { 0xB5A0, 0xB5A0, LBP_H2 },
+       { 0xB5A1, 0xB5BB, LBP_H3 },
+       { 0xB5BC, 0xB5BC, LBP_H2 },
+       { 0xB5BD, 0xB5D7, LBP_H3 },
+       { 0xB5D8, 0xB5D8, LBP_H2 },
+       { 0xB5D9, 0xB5F3, LBP_H3 },
+       { 0xB5F4, 0xB5F4, LBP_H2 },
+       { 0xB5F5, 0xB60F, LBP_H3 },
+       { 0xB610, 0xB610, LBP_H2 },
+       { 0xB611, 0xB62B, LBP_H3 },
+       { 0xB62C, 0xB62C, LBP_H2 },
+       { 0xB62D, 0xB647, LBP_H3 },
+       { 0xB648, 0xB648, LBP_H2 },
+       { 0xB649, 0xB663, LBP_H3 },
+       { 0xB664, 0xB664, LBP_H2 },
+       { 0xB665, 0xB67F, LBP_H3 },
+       { 0xB680, 0xB680, LBP_H2 },
+       { 0xB681, 0xB69B, LBP_H3 },
+       { 0xB69C, 0xB69C, LBP_H2 },
+       { 0xB69D, 0xB6B7, LBP_H3 },
+       { 0xB6B8, 0xB6B8, LBP_H2 },
+       { 0xB6B9, 0xB6D3, LBP_H3 },
+       { 0xB6D4, 0xB6D4, LBP_H2 },
+       { 0xB6D5, 0xB6EF, LBP_H3 },
+       { 0xB6F0, 0xB6F0, LBP_H2 },
+       { 0xB6F1, 0xB70B, LBP_H3 },
+       { 0xB70C, 0xB70C, LBP_H2 },
+       { 0xB70D, 0xB727, LBP_H3 },
+       { 0xB728, 0xB728, LBP_H2 },
+       { 0xB729, 0xB743, LBP_H3 },
+       { 0xB744, 0xB744, LBP_H2 },
+       { 0xB745, 0xB75F, LBP_H3 },
+       { 0xB760, 0xB760, LBP_H2 },
+       { 0xB761, 0xB77B, LBP_H3 },
+       { 0xB77C, 0xB77C, LBP_H2 },
+       { 0xB77D, 0xB797, LBP_H3 },
+       { 0xB798, 0xB798, LBP_H2 },
+       { 0xB799, 0xB7B3, LBP_H3 },
+       { 0xB7B4, 0xB7B4, LBP_H2 },
+       { 0xB7B5, 0xB7CF, LBP_H3 },
+       { 0xB7D0, 0xB7D0, LBP_H2 },
+       { 0xB7D1, 0xB7EB, LBP_H3 },
+       { 0xB7EC, 0xB7EC, LBP_H2 },
+       { 0xB7ED, 0xB807, LBP_H3 },
+       { 0xB808, 0xB808, LBP_H2 },
+       { 0xB809, 0xB823, LBP_H3 },
+       { 0xB824, 0xB824, LBP_H2 },
+       { 0xB825, 0xB83F, LBP_H3 },
+       { 0xB840, 0xB840, LBP_H2 },
+       { 0xB841, 0xB85B, LBP_H3 },
+       { 0xB85C, 0xB85C, LBP_H2 },
+       { 0xB85D, 0xB877, LBP_H3 },
+       { 0xB878, 0xB878, LBP_H2 },
+       { 0xB879, 0xB893, LBP_H3 },
+       { 0xB894, 0xB894, LBP_H2 },
+       { 0xB895, 0xB8AF, LBP_H3 },
+       { 0xB8B0, 0xB8B0, LBP_H2 },
+       { 0xB8B1, 0xB8CB, LBP_H3 },
+       { 0xB8CC, 0xB8CC, LBP_H2 },
+       { 0xB8CD, 0xB8E7, LBP_H3 },
+       { 0xB8E8, 0xB8E8, LBP_H2 },
+       { 0xB8E9, 0xB903, LBP_H3 },
+       { 0xB904, 0xB904, LBP_H2 },
+       { 0xB905, 0xB91F, LBP_H3 },
+       { 0xB920, 0xB920, LBP_H2 },
+       { 0xB921, 0xB93B, LBP_H3 },
+       { 0xB93C, 0xB93C, LBP_H2 },
+       { 0xB93D, 0xB957, LBP_H3 },
+       { 0xB958, 0xB958, LBP_H2 },
+       { 0xB959, 0xB973, LBP_H3 },
+       { 0xB974, 0xB974, LBP_H2 },
+       { 0xB975, 0xB98F, LBP_H3 },
+       { 0xB990, 0xB990, LBP_H2 },
+       { 0xB991, 0xB9AB, LBP_H3 },
+       { 0xB9AC, 0xB9AC, LBP_H2 },
+       { 0xB9AD, 0xB9C7, LBP_H3 },
+       { 0xB9C8, 0xB9C8, LBP_H2 },
+       { 0xB9C9, 0xB9E3, LBP_H3 },
+       { 0xB9E4, 0xB9E4, LBP_H2 },
+       { 0xB9E5, 0xB9FF, LBP_H3 },
+       { 0xBA00, 0xBA00, LBP_H2 },
+       { 0xBA01, 0xBA1B, LBP_H3 },
+       { 0xBA1C, 0xBA1C, LBP_H2 },
+       { 0xBA1D, 0xBA37, LBP_H3 },
+       { 0xBA38, 0xBA38, LBP_H2 },
+       { 0xBA39, 0xBA53, LBP_H3 },
+       { 0xBA54, 0xBA54, LBP_H2 },
+       { 0xBA55, 0xBA6F, LBP_H3 },
+       { 0xBA70, 0xBA70, LBP_H2 },
+       { 0xBA71, 0xBA8B, LBP_H3 },
+       { 0xBA8C, 0xBA8C, LBP_H2 },
+       { 0xBA8D, 0xBAA7, LBP_H3 },
+       { 0xBAA8, 0xBAA8, LBP_H2 },
+       { 0xBAA9, 0xBAC3, LBP_H3 },
+       { 0xBAC4, 0xBAC4, LBP_H2 },
+       { 0xBAC5, 0xBADF, LBP_H3 },
+       { 0xBAE0, 0xBAE0, LBP_H2 },
+       { 0xBAE1, 0xBAFB, LBP_H3 },
+       { 0xBAFC, 0xBAFC, LBP_H2 },
+       { 0xBAFD, 0xBB17, LBP_H3 },
+       { 0xBB18, 0xBB18, LBP_H2 },
+       { 0xBB19, 0xBB33, LBP_H3 },
+       { 0xBB34, 0xBB34, LBP_H2 },
+       { 0xBB35, 0xBB4F, LBP_H3 },
+       { 0xBB50, 0xBB50, LBP_H2 },
+       { 0xBB51, 0xBB6B, LBP_H3 },
+       { 0xBB6C, 0xBB6C, LBP_H2 },
+       { 0xBB6D, 0xBB87, LBP_H3 },
+       { 0xBB88, 0xBB88, LBP_H2 },
+       { 0xBB89, 0xBBA3, LBP_H3 },
+       { 0xBBA4, 0xBBA4, LBP_H2 },
+       { 0xBBA5, 0xBBBF, LBP_H3 },
+       { 0xBBC0, 0xBBC0, LBP_H2 },
+       { 0xBBC1, 0xBBDB, LBP_H3 },
+       { 0xBBDC, 0xBBDC, LBP_H2 },
+       { 0xBBDD, 0xBBF7, LBP_H3 },
+       { 0xBBF8, 0xBBF8, LBP_H2 },
+       { 0xBBF9, 0xBC13, LBP_H3 },
+       { 0xBC14, 0xBC14, LBP_H2 },
+       { 0xBC15, 0xBC2F, LBP_H3 },
+       { 0xBC30, 0xBC30, LBP_H2 },
+       { 0xBC31, 0xBC4B, LBP_H3 },
+       { 0xBC4C, 0xBC4C, LBP_H2 },
+       { 0xBC4D, 0xBC67, LBP_H3 },
+       { 0xBC68, 0xBC68, LBP_H2 },
+       { 0xBC69, 0xBC83, LBP_H3 },
+       { 0xBC84, 0xBC84, LBP_H2 },
+       { 0xBC85, 0xBC9F, LBP_H3 },
+       { 0xBCA0, 0xBCA0, LBP_H2 },
+       { 0xBCA1, 0xBCBB, LBP_H3 },
+       { 0xBCBC, 0xBCBC, LBP_H2 },
+       { 0xBCBD, 0xBCD7, LBP_H3 },
+       { 0xBCD8, 0xBCD8, LBP_H2 },
+       { 0xBCD9, 0xBCF3, LBP_H3 },
+       { 0xBCF4, 0xBCF4, LBP_H2 },
+       { 0xBCF5, 0xBD0F, LBP_H3 },
+       { 0xBD10, 0xBD10, LBP_H2 },
+       { 0xBD11, 0xBD2B, LBP_H3 },
+       { 0xBD2C, 0xBD2C, LBP_H2 },
+       { 0xBD2D, 0xBD47, LBP_H3 },
+       { 0xBD48, 0xBD48, LBP_H2 },
+       { 0xBD49, 0xBD63, LBP_H3 },
+       { 0xBD64, 0xBD64, LBP_H2 },
+       { 0xBD65, 0xBD7F, LBP_H3 },
+       { 0xBD80, 0xBD80, LBP_H2 },
+       { 0xBD81, 0xBD9B, LBP_H3 },
+       { 0xBD9C, 0xBD9C, LBP_H2 },
+       { 0xBD9D, 0xBDB7, LBP_H3 },
+       { 0xBDB8, 0xBDB8, LBP_H2 },
+       { 0xBDB9, 0xBDD3, LBP_H3 },
+       { 0xBDD4, 0xBDD4, LBP_H2 },
+       { 0xBDD5, 0xBDEF, LBP_H3 },
+       { 0xBDF0, 0xBDF0, LBP_H2 },
+       { 0xBDF1, 0xBE0B, LBP_H3 },
+       { 0xBE0C, 0xBE0C, LBP_H2 },
+       { 0xBE0D, 0xBE27, LBP_H3 },
+       { 0xBE28, 0xBE28, LBP_H2 },
+       { 0xBE29, 0xBE43, LBP_H3 },
+       { 0xBE44, 0xBE44, LBP_H2 },
+       { 0xBE45, 0xBE5F, LBP_H3 },
+       { 0xBE60, 0xBE60, LBP_H2 },
+       { 0xBE61, 0xBE7B, LBP_H3 },
+       { 0xBE7C, 0xBE7C, LBP_H2 },
+       { 0xBE7D, 0xBE97, LBP_H3 },
+       { 0xBE98, 0xBE98, LBP_H2 },
+       { 0xBE99, 0xBEB3, LBP_H3 },
+       { 0xBEB4, 0xBEB4, LBP_H2 },
+       { 0xBEB5, 0xBECF, LBP_H3 },
+       { 0xBED0, 0xBED0, LBP_H2 },
+       { 0xBED1, 0xBEEB, LBP_H3 },
+       { 0xBEEC, 0xBEEC, LBP_H2 },
+       { 0xBEED, 0xBF07, LBP_H3 },
+       { 0xBF08, 0xBF08, LBP_H2 },
+       { 0xBF09, 0xBF23, LBP_H3 },
+       { 0xBF24, 0xBF24, LBP_H2 },
+       { 0xBF25, 0xBF3F, LBP_H3 },
+       { 0xBF40, 0xBF40, LBP_H2 },
+       { 0xBF41, 0xBF5B, LBP_H3 },
+       { 0xBF5C, 0xBF5C, LBP_H2 },
+       { 0xBF5D, 0xBF77, LBP_H3 },
+       { 0xBF78, 0xBF78, LBP_H2 },
+       { 0xBF79, 0xBF93, LBP_H3 },
+       { 0xBF94, 0xBF94, LBP_H2 },
+       { 0xBF95, 0xBFAF, LBP_H3 },
+       { 0xBFB0, 0xBFB0, LBP_H2 },
+       { 0xBFB1, 0xBFCB, LBP_H3 },
+       { 0xBFCC, 0xBFCC, LBP_H2 },
+       { 0xBFCD, 0xBFE7, LBP_H3 },
+       { 0xBFE8, 0xBFE8, LBP_H2 },
+       { 0xBFE9, 0xC003, LBP_H3 },
+       { 0xC004, 0xC004, LBP_H2 },
+       { 0xC005, 0xC01F, LBP_H3 },
+       { 0xC020, 0xC020, LBP_H2 },
+       { 0xC021, 0xC03B, LBP_H3 },
+       { 0xC03C, 0xC03C, LBP_H2 },
+       { 0xC03D, 0xC057, LBP_H3 },
+       { 0xC058, 0xC058, LBP_H2 },
+       { 0xC059, 0xC073, LBP_H3 },
+       { 0xC074, 0xC074, LBP_H2 },
+       { 0xC075, 0xC08F, LBP_H3 },
+       { 0xC090, 0xC090, LBP_H2 },
+       { 0xC091, 0xC0AB, LBP_H3 },
+       { 0xC0AC, 0xC0AC, LBP_H2 },
+       { 0xC0AD, 0xC0C7, LBP_H3 },
+       { 0xC0C8, 0xC0C8, LBP_H2 },
+       { 0xC0C9, 0xC0E3, LBP_H3 },
+       { 0xC0E4, 0xC0E4, LBP_H2 },
+       { 0xC0E5, 0xC0FF, LBP_H3 },
+       { 0xC100, 0xC100, LBP_H2 },
+       { 0xC101, 0xC11B, LBP_H3 },
+       { 0xC11C, 0xC11C, LBP_H2 },
+       { 0xC11D, 0xC137, LBP_H3 },
+       { 0xC138, 0xC138, LBP_H2 },
+       { 0xC139, 0xC153, LBP_H3 },
+       { 0xC154, 0xC154, LBP_H2 },
+       { 0xC155, 0xC16F, LBP_H3 },
+       { 0xC170, 0xC170, LBP_H2 },
+       { 0xC171, 0xC18B, LBP_H3 },
+       { 0xC18C, 0xC18C, LBP_H2 },
+       { 0xC18D, 0xC1A7, LBP_H3 },
+       { 0xC1A8, 0xC1A8, LBP_H2 },
+       { 0xC1A9, 0xC1C3, LBP_H3 },
+       { 0xC1C4, 0xC1C4, LBP_H2 },
+       { 0xC1C5, 0xC1DF, LBP_H3 },
+       { 0xC1E0, 0xC1E0, LBP_H2 },
+       { 0xC1E1, 0xC1FB, LBP_H3 },
+       { 0xC1FC, 0xC1FC, LBP_H2 },
+       { 0xC1FD, 0xC217, LBP_H3 },
+       { 0xC218, 0xC218, LBP_H2 },
+       { 0xC219, 0xC233, LBP_H3 },
+       { 0xC234, 0xC234, LBP_H2 },
+       { 0xC235, 0xC24F, LBP_H3 },
+       { 0xC250, 0xC250, LBP_H2 },
+       { 0xC251, 0xC26B, LBP_H3 },
+       { 0xC26C, 0xC26C, LBP_H2 },
+       { 0xC26D, 0xC287, LBP_H3 },
+       { 0xC288, 0xC288, LBP_H2 },
+       { 0xC289, 0xC2A3, LBP_H3 },
+       { 0xC2A4, 0xC2A4, LBP_H2 },
+       { 0xC2A5, 0xC2BF, LBP_H3 },
+       { 0xC2C0, 0xC2C0, LBP_H2 },
+       { 0xC2C1, 0xC2DB, LBP_H3 },
+       { 0xC2DC, 0xC2DC, LBP_H2 },
+       { 0xC2DD, 0xC2F7, LBP_H3 },
+       { 0xC2F8, 0xC2F8, LBP_H2 },
+       { 0xC2F9, 0xC313, LBP_H3 },
+       { 0xC314, 0xC314, LBP_H2 },
+       { 0xC315, 0xC32F, LBP_H3 },
+       { 0xC330, 0xC330, LBP_H2 },
+       { 0xC331, 0xC34B, LBP_H3 },
+       { 0xC34C, 0xC34C, LBP_H2 },
+       { 0xC34D, 0xC367, LBP_H3 },
+       { 0xC368, 0xC368, LBP_H2 },
+       { 0xC369, 0xC383, LBP_H3 },
+       { 0xC384, 0xC384, LBP_H2 },
+       { 0xC385, 0xC39F, LBP_H3 },
+       { 0xC3A0, 0xC3A0, LBP_H2 },
+       { 0xC3A1, 0xC3BB, LBP_H3 },
+       { 0xC3BC, 0xC3BC, LBP_H2 },
+       { 0xC3BD, 0xC3D7, LBP_H3 },
+       { 0xC3D8, 0xC3D8, LBP_H2 },
+       { 0xC3D9, 0xC3F3, LBP_H3 },
+       { 0xC3F4, 0xC3F4, LBP_H2 },
+       { 0xC3F5, 0xC40F, LBP_H3 },
+       { 0xC410, 0xC410, LBP_H2 },
+       { 0xC411, 0xC42B, LBP_H3 },
+       { 0xC42C, 0xC42C, LBP_H2 },
+       { 0xC42D, 0xC447, LBP_H3 },
+       { 0xC448, 0xC448, LBP_H2 },
+       { 0xC449, 0xC463, LBP_H3 },
+       { 0xC464, 0xC464, LBP_H2 },
+       { 0xC465, 0xC47F, LBP_H3 },
+       { 0xC480, 0xC480, LBP_H2 },
+       { 0xC481, 0xC49B, LBP_H3 },
+       { 0xC49C, 0xC49C, LBP_H2 },
+       { 0xC49D, 0xC4B7, LBP_H3 },
+       { 0xC4B8, 0xC4B8, LBP_H2 },
+       { 0xC4B9, 0xC4D3, LBP_H3 },
+       { 0xC4D4, 0xC4D4, LBP_H2 },
+       { 0xC4D5, 0xC4EF, LBP_H3 },
+       { 0xC4F0, 0xC4F0, LBP_H2 },
+       { 0xC4F1, 0xC50B, LBP_H3 },
+       { 0xC50C, 0xC50C, LBP_H2 },
+       { 0xC50D, 0xC527, LBP_H3 },
+       { 0xC528, 0xC528, LBP_H2 },
+       { 0xC529, 0xC543, LBP_H3 },
+       { 0xC544, 0xC544, LBP_H2 },
+       { 0xC545, 0xC55F, LBP_H3 },
+       { 0xC560, 0xC560, LBP_H2 },
+       { 0xC561, 0xC57B, LBP_H3 },
+       { 0xC57C, 0xC57C, LBP_H2 },
+       { 0xC57D, 0xC597, LBP_H3 },
+       { 0xC598, 0xC598, LBP_H2 },
+       { 0xC599, 0xC5B3, LBP_H3 },
+       { 0xC5B4, 0xC5B4, LBP_H2 },
+       { 0xC5B5, 0xC5CF, LBP_H3 },
+       { 0xC5D0, 0xC5D0, LBP_H2 },
+       { 0xC5D1, 0xC5EB, LBP_H3 },
+       { 0xC5EC, 0xC5EC, LBP_H2 },
+       { 0xC5ED, 0xC607, LBP_H3 },
+       { 0xC608, 0xC608, LBP_H2 },
+       { 0xC609, 0xC623, LBP_H3 },
+       { 0xC624, 0xC624, LBP_H2 },
+       { 0xC625, 0xC63F, LBP_H3 },
+       { 0xC640, 0xC640, LBP_H2 },
+       { 0xC641, 0xC65B, LBP_H3 },
+       { 0xC65C, 0xC65C, LBP_H2 },
+       { 0xC65D, 0xC677, LBP_H3 },
+       { 0xC678, 0xC678, LBP_H2 },
+       { 0xC679, 0xC693, LBP_H3 },
+       { 0xC694, 0xC694, LBP_H2 },
+       { 0xC695, 0xC6AF, LBP_H3 },
+       { 0xC6B0, 0xC6B0, LBP_H2 },
+       { 0xC6B1, 0xC6CB, LBP_H3 },
+       { 0xC6CC, 0xC6CC, LBP_H2 },
+       { 0xC6CD, 0xC6E7, LBP_H3 },
+       { 0xC6E8, 0xC6E8, LBP_H2 },
+       { 0xC6E9, 0xC703, LBP_H3 },
+       { 0xC704, 0xC704, LBP_H2 },
+       { 0xC705, 0xC71F, LBP_H3 },
+       { 0xC720, 0xC720, LBP_H2 },
+       { 0xC721, 0xC73B, LBP_H3 },
+       { 0xC73C, 0xC73C, LBP_H2 },
+       { 0xC73D, 0xC757, LBP_H3 },
+       { 0xC758, 0xC758, LBP_H2 },
+       { 0xC759, 0xC773, LBP_H3 },
+       { 0xC774, 0xC774, LBP_H2 },
+       { 0xC775, 0xC78F, LBP_H3 },
+       { 0xC790, 0xC790, LBP_H2 },
+       { 0xC791, 0xC7AB, LBP_H3 },
+       { 0xC7AC, 0xC7AC, LBP_H2 },
+       { 0xC7AD, 0xC7C7, LBP_H3 },
+       { 0xC7C8, 0xC7C8, LBP_H2 },
+       { 0xC7C9, 0xC7E3, LBP_H3 },
+       { 0xC7E4, 0xC7E4, LBP_H2 },
+       { 0xC7E5, 0xC7FF, LBP_H3 },
+       { 0xC800, 0xC800, LBP_H2 },
+       { 0xC801, 0xC81B, LBP_H3 },
+       { 0xC81C, 0xC81C, LBP_H2 },
+       { 0xC81D, 0xC837, LBP_H3 },
+       { 0xC838, 0xC838, LBP_H2 },
+       { 0xC839, 0xC853, LBP_H3 },
+       { 0xC854, 0xC854, LBP_H2 },
+       { 0xC855, 0xC86F, LBP_H3 },
+       { 0xC870, 0xC870, LBP_H2 },
+       { 0xC871, 0xC88B, LBP_H3 },
+       { 0xC88C, 0xC88C, LBP_H2 },
+       { 0xC88D, 0xC8A7, LBP_H3 },
+       { 0xC8A8, 0xC8A8, LBP_H2 },
+       { 0xC8A9, 0xC8C3, LBP_H3 },
+       { 0xC8C4, 0xC8C4, LBP_H2 },
+       { 0xC8C5, 0xC8DF, LBP_H3 },
+       { 0xC8E0, 0xC8E0, LBP_H2 },
+       { 0xC8E1, 0xC8FB, LBP_H3 },
+       { 0xC8FC, 0xC8FC, LBP_H2 },
+       { 0xC8FD, 0xC917, LBP_H3 },
+       { 0xC918, 0xC918, LBP_H2 },
+       { 0xC919, 0xC933, LBP_H3 },
+       { 0xC934, 0xC934, LBP_H2 },
+       { 0xC935, 0xC94F, LBP_H3 },
+       { 0xC950, 0xC950, LBP_H2 },
+       { 0xC951, 0xC96B, LBP_H3 },
+       { 0xC96C, 0xC96C, LBP_H2 },
+       { 0xC96D, 0xC987, LBP_H3 },
+       { 0xC988, 0xC988, LBP_H2 },
+       { 0xC989, 0xC9A3, LBP_H3 },
+       { 0xC9A4, 0xC9A4, LBP_H2 },
+       { 0xC9A5, 0xC9BF, LBP_H3 },
+       { 0xC9C0, 0xC9C0, LBP_H2 },
+       { 0xC9C1, 0xC9DB, LBP_H3 },
+       { 0xC9DC, 0xC9DC, LBP_H2 },
+       { 0xC9DD, 0xC9F7, LBP_H3 },
+       { 0xC9F8, 0xC9F8, LBP_H2 },
+       { 0xC9F9, 0xCA13, LBP_H3 },
+       { 0xCA14, 0xCA14, LBP_H2 },
+       { 0xCA15, 0xCA2F, LBP_H3 },
+       { 0xCA30, 0xCA30, LBP_H2 },
+       { 0xCA31, 0xCA4B, LBP_H3 },
+       { 0xCA4C, 0xCA4C, LBP_H2 },
+       { 0xCA4D, 0xCA67, LBP_H3 },
+       { 0xCA68, 0xCA68, LBP_H2 },
+       { 0xCA69, 0xCA83, LBP_H3 },
+       { 0xCA84, 0xCA84, LBP_H2 },
+       { 0xCA85, 0xCA9F, LBP_H3 },
+       { 0xCAA0, 0xCAA0, LBP_H2 },
+       { 0xCAA1, 0xCABB, LBP_H3 },
+       { 0xCABC, 0xCABC, LBP_H2 },
+       { 0xCABD, 0xCAD7, LBP_H3 },
+       { 0xCAD8, 0xCAD8, LBP_H2 },
+       { 0xCAD9, 0xCAF3, LBP_H3 },
+       { 0xCAF4, 0xCAF4, LBP_H2 },
+       { 0xCAF5, 0xCB0F, LBP_H3 },
+       { 0xCB10, 0xCB10, LBP_H2 },
+       { 0xCB11, 0xCB2B, LBP_H3 },
+       { 0xCB2C, 0xCB2C, LBP_H2 },
+       { 0xCB2D, 0xCB47, LBP_H3 },
+       { 0xCB48, 0xCB48, LBP_H2 },
+       { 0xCB49, 0xCB63, LBP_H3 },
+       { 0xCB64, 0xCB64, LBP_H2 },
+       { 0xCB65, 0xCB7F, LBP_H3 },
+       { 0xCB80, 0xCB80, LBP_H2 },
+       { 0xCB81, 0xCB9B, LBP_H3 },
+       { 0xCB9C, 0xCB9C, LBP_H2 },
+       { 0xCB9D, 0xCBB7, LBP_H3 },
+       { 0xCBB8, 0xCBB8, LBP_H2 },
+       { 0xCBB9, 0xCBD3, LBP_H3 },
+       { 0xCBD4, 0xCBD4, LBP_H2 },
+       { 0xCBD5, 0xCBEF, LBP_H3 },
+       { 0xCBF0, 0xCBF0, LBP_H2 },
+       { 0xCBF1, 0xCC0B, LBP_H3 },
+       { 0xCC0C, 0xCC0C, LBP_H2 },
+       { 0xCC0D, 0xCC27, LBP_H3 },
+       { 0xCC28, 0xCC28, LBP_H2 },
+       { 0xCC29, 0xCC43, LBP_H3 },
+       { 0xCC44, 0xCC44, LBP_H2 },
+       { 0xCC45, 0xCC5F, LBP_H3 },
+       { 0xCC60, 0xCC60, LBP_H2 },
+       { 0xCC61, 0xCC7B, LBP_H3 },
+       { 0xCC7C, 0xCC7C, LBP_H2 },
+       { 0xCC7D, 0xCC97, LBP_H3 },
+       { 0xCC98, 0xCC98, LBP_H2 },
+       { 0xCC99, 0xCCB3, LBP_H3 },
+       { 0xCCB4, 0xCCB4, LBP_H2 },
+       { 0xCCB5, 0xCCCF, LBP_H3 },
+       { 0xCCD0, 0xCCD0, LBP_H2 },
+       { 0xCCD1, 0xCCEB, LBP_H3 },
+       { 0xCCEC, 0xCCEC, LBP_H2 },
+       { 0xCCED, 0xCD07, LBP_H3 },
+       { 0xCD08, 0xCD08, LBP_H2 },
+       { 0xCD09, 0xCD23, LBP_H3 },
+       { 0xCD24, 0xCD24, LBP_H2 },
+       { 0xCD25, 0xCD3F, LBP_H3 },
+       { 0xCD40, 0xCD40, LBP_H2 },
+       { 0xCD41, 0xCD5B, LBP_H3 },
+       { 0xCD5C, 0xCD5C, LBP_H2 },
+       { 0xCD5D, 0xCD77, LBP_H3 },
+       { 0xCD78, 0xCD78, LBP_H2 },
+       { 0xCD79, 0xCD93, LBP_H3 },
+       { 0xCD94, 0xCD94, LBP_H2 },
+       { 0xCD95, 0xCDAF, LBP_H3 },
+       { 0xCDB0, 0xCDB0, LBP_H2 },
+       { 0xCDB1, 0xCDCB, LBP_H3 },
+       { 0xCDCC, 0xCDCC, LBP_H2 },
+       { 0xCDCD, 0xCDE7, LBP_H3 },
+       { 0xCDE8, 0xCDE8, LBP_H2 },
+       { 0xCDE9, 0xCE03, LBP_H3 },
+       { 0xCE04, 0xCE04, LBP_H2 },
+       { 0xCE05, 0xCE1F, LBP_H3 },
+       { 0xCE20, 0xCE20, LBP_H2 },
+       { 0xCE21, 0xCE3B, LBP_H3 },
+       { 0xCE3C, 0xCE3C, LBP_H2 },
+       { 0xCE3D, 0xCE57, LBP_H3 },
+       { 0xCE58, 0xCE58, LBP_H2 },
+       { 0xCE59, 0xCE73, LBP_H3 },
+       { 0xCE74, 0xCE74, LBP_H2 },
+       { 0xCE75, 0xCE8F, LBP_H3 },
+       { 0xCE90, 0xCE90, LBP_H2 },
+       { 0xCE91, 0xCEAB, LBP_H3 },
+       { 0xCEAC, 0xCEAC, LBP_H2 },
+       { 0xCEAD, 0xCEC7, LBP_H3 },
+       { 0xCEC8, 0xCEC8, LBP_H2 },
+       { 0xCEC9, 0xCEE3, LBP_H3 },
+       { 0xCEE4, 0xCEE4, LBP_H2 },
+       { 0xCEE5, 0xCEFF, LBP_H3 },
+       { 0xCF00, 0xCF00, LBP_H2 },
+       { 0xCF01, 0xCF1B, LBP_H3 },
+       { 0xCF1C, 0xCF1C, LBP_H2 },
+       { 0xCF1D, 0xCF37, LBP_H3 },
+       { 0xCF38, 0xCF38, LBP_H2 },
+       { 0xCF39, 0xCF53, LBP_H3 },
+       { 0xCF54, 0xCF54, LBP_H2 },
+       { 0xCF55, 0xCF6F, LBP_H3 },
+       { 0xCF70, 0xCF70, LBP_H2 },
+       { 0xCF71, 0xCF8B, LBP_H3 },
+       { 0xCF8C, 0xCF8C, LBP_H2 },
+       { 0xCF8D, 0xCFA7, LBP_H3 },
+       { 0xCFA8, 0xCFA8, LBP_H2 },
+       { 0xCFA9, 0xCFC3, LBP_H3 },
+       { 0xCFC4, 0xCFC4, LBP_H2 },
+       { 0xCFC5, 0xCFDF, LBP_H3 },
+       { 0xCFE0, 0xCFE0, LBP_H2 },
+       { 0xCFE1, 0xCFFB, LBP_H3 },
+       { 0xCFFC, 0xCFFC, LBP_H2 },
+       { 0xCFFD, 0xD017, LBP_H3 },
+       { 0xD018, 0xD018, LBP_H2 },
+       { 0xD019, 0xD033, LBP_H3 },
+       { 0xD034, 0xD034, LBP_H2 },
+       { 0xD035, 0xD04F, LBP_H3 },
+       { 0xD050, 0xD050, LBP_H2 },
+       { 0xD051, 0xD06B, LBP_H3 },
+       { 0xD06C, 0xD06C, LBP_H2 },
+       { 0xD06D, 0xD087, LBP_H3 },
+       { 0xD088, 0xD088, LBP_H2 },
+       { 0xD089, 0xD0A3, LBP_H3 },
+       { 0xD0A4, 0xD0A4, LBP_H2 },
+       { 0xD0A5, 0xD0BF, LBP_H3 },
+       { 0xD0C0, 0xD0C0, LBP_H2 },
+       { 0xD0C1, 0xD0DB, LBP_H3 },
+       { 0xD0DC, 0xD0DC, LBP_H2 },
+       { 0xD0DD, 0xD0F7, LBP_H3 },
+       { 0xD0F8, 0xD0F8, LBP_H2 },
+       { 0xD0F9, 0xD113, LBP_H3 },
+       { 0xD114, 0xD114, LBP_H2 },
+       { 0xD115, 0xD12F, LBP_H3 },
+       { 0xD130, 0xD130, LBP_H2 },
+       { 0xD131, 0xD14B, LBP_H3 },
+       { 0xD14C, 0xD14C, LBP_H2 },
+       { 0xD14D, 0xD167, LBP_H3 },
+       { 0xD168, 0xD168, LBP_H2 },
+       { 0xD169, 0xD183, LBP_H3 },
+       { 0xD184, 0xD184, LBP_H2 },
+       { 0xD185, 0xD19F, LBP_H3 },
+       { 0xD1A0, 0xD1A0, LBP_H2 },
+       { 0xD1A1, 0xD1BB, LBP_H3 },
+       { 0xD1BC, 0xD1BC, LBP_H2 },
+       { 0xD1BD, 0xD1D7, LBP_H3 },
+       { 0xD1D8, 0xD1D8, LBP_H2 },
+       { 0xD1D9, 0xD1F3, LBP_H3 },
+       { 0xD1F4, 0xD1F4, LBP_H2 },
+       { 0xD1F5, 0xD20F, LBP_H3 },
+       { 0xD210, 0xD210, LBP_H2 },
+       { 0xD211, 0xD22B, LBP_H3 },
+       { 0xD22C, 0xD22C, LBP_H2 },
+       { 0xD22D, 0xD247, LBP_H3 },
+       { 0xD248, 0xD248, LBP_H2 },
+       { 0xD249, 0xD263, LBP_H3 },
+       { 0xD264, 0xD264, LBP_H2 },
+       { 0xD265, 0xD27F, LBP_H3 },
+       { 0xD280, 0xD280, LBP_H2 },
+       { 0xD281, 0xD29B, LBP_H3 },
+       { 0xD29C, 0xD29C, LBP_H2 },
+       { 0xD29D, 0xD2B7, LBP_H3 },
+       { 0xD2B8, 0xD2B8, LBP_H2 },
+       { 0xD2B9, 0xD2D3, LBP_H3 },
+       { 0xD2D4, 0xD2D4, LBP_H2 },
+       { 0xD2D5, 0xD2EF, LBP_H3 },
+       { 0xD2F0, 0xD2F0, LBP_H2 },
+       { 0xD2F1, 0xD30B, LBP_H3 },
+       { 0xD30C, 0xD30C, LBP_H2 },
+       { 0xD30D, 0xD327, LBP_H3 },
+       { 0xD328, 0xD328, LBP_H2 },
+       { 0xD329, 0xD343, LBP_H3 },
+       { 0xD344, 0xD344, LBP_H2 },
+       { 0xD345, 0xD35F, LBP_H3 },
+       { 0xD360, 0xD360, LBP_H2 },
+       { 0xD361, 0xD37B, LBP_H3 },
+       { 0xD37C, 0xD37C, LBP_H2 },
+       { 0xD37D, 0xD397, LBP_H3 },
+       { 0xD398, 0xD398, LBP_H2 },
+       { 0xD399, 0xD3B3, LBP_H3 },
+       { 0xD3B4, 0xD3B4, LBP_H2 },
+       { 0xD3B5, 0xD3CF, LBP_H3 },
+       { 0xD3D0, 0xD3D0, LBP_H2 },
+       { 0xD3D1, 0xD3EB, LBP_H3 },
+       { 0xD3EC, 0xD3EC, LBP_H2 },
+       { 0xD3ED, 0xD407, LBP_H3 },
+       { 0xD408, 0xD408, LBP_H2 },
+       { 0xD409, 0xD423, LBP_H3 },
+       { 0xD424, 0xD424, LBP_H2 },
+       { 0xD425, 0xD43F, LBP_H3 },
+       { 0xD440, 0xD440, LBP_H2 },
+       { 0xD441, 0xD45B, LBP_H3 },
+       { 0xD45C, 0xD45C, LBP_H2 },
+       { 0xD45D, 0xD477, LBP_H3 },
+       { 0xD478, 0xD478, LBP_H2 },
+       { 0xD479, 0xD493, LBP_H3 },
+       { 0xD494, 0xD494, LBP_H2 },
+       { 0xD495, 0xD4AF, LBP_H3 },
+       { 0xD4B0, 0xD4B0, LBP_H2 },
+       { 0xD4B1, 0xD4CB, LBP_H3 },
+       { 0xD4CC, 0xD4CC, LBP_H2 },
+       { 0xD4CD, 0xD4E7, LBP_H3 },
+       { 0xD4E8, 0xD4E8, LBP_H2 },
+       { 0xD4E9, 0xD503, LBP_H3 },
+       { 0xD504, 0xD504, LBP_H2 },
+       { 0xD505, 0xD51F, LBP_H3 },
+       { 0xD520, 0xD520, LBP_H2 },
+       { 0xD521, 0xD53B, LBP_H3 },
+       { 0xD53C, 0xD53C, LBP_H2 },
+       { 0xD53D, 0xD557, LBP_H3 },
+       { 0xD558, 0xD558, LBP_H2 },
+       { 0xD559, 0xD573, LBP_H3 },
+       { 0xD574, 0xD574, LBP_H2 },
+       { 0xD575, 0xD58F, LBP_H3 },
+       { 0xD590, 0xD590, LBP_H2 },
+       { 0xD591, 0xD5AB, LBP_H3 },
+       { 0xD5AC, 0xD5AC, LBP_H2 },
+       { 0xD5AD, 0xD5C7, LBP_H3 },
+       { 0xD5C8, 0xD5C8, LBP_H2 },
+       { 0xD5C9, 0xD5E3, LBP_H3 },
+       { 0xD5E4, 0xD5E4, LBP_H2 },
+       { 0xD5E5, 0xD5FF, LBP_H3 },
+       { 0xD600, 0xD600, LBP_H2 },
+       { 0xD601, 0xD61B, LBP_H3 },
+       { 0xD61C, 0xD61C, LBP_H2 },
+       { 0xD61D, 0xD637, LBP_H3 },
+       { 0xD638, 0xD638, LBP_H2 },
+       { 0xD639, 0xD653, LBP_H3 },
+       { 0xD654, 0xD654, LBP_H2 },
+       { 0xD655, 0xD66F, LBP_H3 },
+       { 0xD670, 0xD670, LBP_H2 },
+       { 0xD671, 0xD68B, LBP_H3 },
+       { 0xD68C, 0xD68C, LBP_H2 },
+       { 0xD68D, 0xD6A7, LBP_H3 },
+       { 0xD6A8, 0xD6A8, LBP_H2 },
+       { 0xD6A9, 0xD6C3, LBP_H3 },
+       { 0xD6C4, 0xD6C4, LBP_H2 },
+       { 0xD6C5, 0xD6DF, LBP_H3 },
+       { 0xD6E0, 0xD6E0, LBP_H2 },
+       { 0xD6E1, 0xD6FB, LBP_H3 },
+       { 0xD6FC, 0xD6FC, LBP_H2 },
+       { 0xD6FD, 0xD717, LBP_H3 },
+       { 0xD718, 0xD718, LBP_H2 },
+       { 0xD719, 0xD733, LBP_H3 },
+       { 0xD734, 0xD734, LBP_H2 },
+       { 0xD735, 0xD74F, LBP_H3 },
+       { 0xD750, 0xD750, LBP_H2 },
+       { 0xD751, 0xD76B, LBP_H3 },
+       { 0xD76C, 0xD76C, LBP_H2 },
+       { 0xD76D, 0xD787, LBP_H3 },
+       { 0xD788, 0xD788, LBP_H2 },
+       { 0xD789, 0xD7A3, LBP_H3 },
+       { 0xD7B0, 0xD7C6, LBP_JV },
+       { 0xD7CB, 0xD7FB, LBP_JT },
+       { 0xD800, 0xDFFF, LBP_SG },
+       { 0xE000, 0xF8FF, LBP_XX },
+       { 0xF900, 0xFAFF, LBP_ID },
+       { 0xFB00, 0xFB17, LBP_AL },
+       { 0xFB1D, 0xFB1D, LBP_HL },
+       { 0xFB1E, 0xFB1E, LBP_CM },
+       { 0xFB1F, 0xFB28, LBP_HL },
+       { 0xFB29, 0xFB29, LBP_AL },
+       { 0xFB2A, 0xFB4F, LBP_HL },
+       { 0xFB50, 0xFD3D, LBP_AL },
+       { 0xFD3E, 0xFD3E, LBP_CL },
+       { 0xFD3F, 0xFD3F, LBP_OP },
+       { 0xFD50, 0xFDFB, LBP_AL },
+       { 0xFDFC, 0xFDFC, LBP_PO },
+       { 0xFDFD, 0xFDFD, LBP_AL },
+       { 0xFE00, 0xFE0F, LBP_CM },
+       { 0xFE10, 0xFE10, LBP_IS },
+       { 0xFE11, 0xFE12, LBP_CL },
+       { 0xFE13, 0xFE14, LBP_IS },
+       { 0xFE15, 0xFE16, LBP_EX },
+       { 0xFE17, 0xFE17, LBP_OP },
+       { 0xFE18, 0xFE18, LBP_CL },
+       { 0xFE19, 0xFE19, LBP_IN },
+       { 0xFE20, 0xFE2D, LBP_CM },
+       { 0xFE30, 0xFE34, LBP_ID },
+       { 0xFE35, 0xFE35, LBP_OP },
+       { 0xFE36, 0xFE36, LBP_CL },
+       { 0xFE37, 0xFE37, LBP_OP },
+       { 0xFE38, 0xFE38, LBP_CL },
+       { 0xFE39, 0xFE39, LBP_OP },
+       { 0xFE3A, 0xFE3A, LBP_CL },
+       { 0xFE3B, 0xFE3B, LBP_OP },
+       { 0xFE3C, 0xFE3C, LBP_CL },
+       { 0xFE3D, 0xFE3D, LBP_OP },
+       { 0xFE3E, 0xFE3E, LBP_CL },
+       { 0xFE3F, 0xFE3F, LBP_OP },
+       { 0xFE40, 0xFE40, LBP_CL },
+       { 0xFE41, 0xFE41, LBP_OP },
+       { 0xFE42, 0xFE42, LBP_CL },
+       { 0xFE43, 0xFE43, LBP_OP },
+       { 0xFE44, 0xFE44, LBP_CL },
+       { 0xFE45, 0xFE46, LBP_ID },
+       { 0xFE47, 0xFE47, LBP_OP },
+       { 0xFE48, 0xFE48, LBP_CL },
+       { 0xFE49, 0xFE4F, LBP_ID },
+       { 0xFE50, 0xFE50, LBP_CL },
+       { 0xFE51, 0xFE51, LBP_ID },
+       { 0xFE52, 0xFE52, LBP_CL },
+       { 0xFE54, 0xFE55, LBP_NS },
+       { 0xFE56, 0xFE57, LBP_EX },
+       { 0xFE58, 0xFE58, LBP_ID },
+       { 0xFE59, 0xFE59, LBP_OP },
+       { 0xFE5A, 0xFE5A, LBP_CL },
+       { 0xFE5B, 0xFE5B, LBP_OP },
+       { 0xFE5C, 0xFE5C, LBP_CL },
+       { 0xFE5D, 0xFE5D, LBP_OP },
+       { 0xFE5E, 0xFE5E, LBP_CL },
+       { 0xFE5F, 0xFE68, LBP_ID },
+       { 0xFE69, 0xFE69, LBP_PR },
+       { 0xFE6A, 0xFE6A, LBP_PO },
+       { 0xFE6B, 0xFE6B, LBP_ID },
+       { 0xFE70, 0xFEFC, LBP_AL },
+       { 0xFEFF, 0xFEFF, LBP_WJ },
+       { 0xFF01, 0xFF01, LBP_EX },
+       { 0xFF02, 0xFF03, LBP_ID },
+       { 0xFF04, 0xFF04, LBP_PR },
+       { 0xFF05, 0xFF05, LBP_PO },
+       { 0xFF06, 0xFF07, LBP_ID },
+       { 0xFF08, 0xFF08, LBP_OP },
+       { 0xFF09, 0xFF09, LBP_CL },
+       { 0xFF0A, 0xFF0B, LBP_ID },
+       { 0xFF0C, 0xFF0C, LBP_CL },
+       { 0xFF0D, 0xFF0D, LBP_ID },
+       { 0xFF0E, 0xFF0E, LBP_CL },
+       { 0xFF0F, 0xFF19, LBP_ID },
+       { 0xFF1A, 0xFF1B, LBP_NS },
+       { 0xFF1C, 0xFF1E, LBP_ID },
+       { 0xFF1F, 0xFF1F, LBP_EX },
+       { 0xFF20, 0xFF3A, LBP_ID },
+       { 0xFF3B, 0xFF3B, LBP_OP },
+       { 0xFF3C, 0xFF3C, LBP_ID },
+       { 0xFF3D, 0xFF3D, LBP_CL },
+       { 0xFF3E, 0xFF5A, LBP_ID },
+       { 0xFF5B, 0xFF5B, LBP_OP },
+       { 0xFF5C, 0xFF5C, LBP_ID },
+       { 0xFF5D, 0xFF5D, LBP_CL },
+       { 0xFF5E, 0xFF5E, LBP_ID },
+       { 0xFF5F, 0xFF5F, LBP_OP },
+       { 0xFF60, 0xFF61, LBP_CL },
+       { 0xFF62, 0xFF62, LBP_OP },
+       { 0xFF63, 0xFF64, LBP_CL },
+       { 0xFF65, 0xFF65, LBP_NS },
+       { 0xFF66, 0xFF66, LBP_AL },
+       { 0xFF67, 0xFF70, LBP_CJ },
+       { 0xFF71, 0xFF9D, LBP_AL },
+       { 0xFF9E, 0xFF9F, LBP_NS },
+       { 0xFFA0, 0xFFDC, LBP_AL },
+       { 0xFFE0, 0xFFE0, LBP_PO },
+       { 0xFFE1, 0xFFE1, LBP_PR },
+       { 0xFFE2, 0xFFE4, LBP_ID },
+       { 0xFFE5, 0xFFE6, LBP_PR },
+       { 0xFFE8, 0xFFEE, LBP_AL },
+       { 0xFFF9, 0xFFFB, LBP_CM },
+       { 0xFFFC, 0xFFFC, LBP_CB },
+       { 0xFFFD, 0xFFFD, LBP_AI },
+       { 0x10000, 0x100FA, LBP_AL },
+       { 0x10100, 0x10102, LBP_BA },
+       { 0x10107, 0x101FC, LBP_AL },
+       { 0x101FD, 0x101FD, LBP_CM },
+       { 0x10280, 0x102D0, LBP_AL },
+       { 0x102E0, 0x102E0, LBP_CM },
+       { 0x102E1, 0x10375, LBP_AL },
+       { 0x10376, 0x1037A, LBP_CM },
+       { 0x10380, 0x1039D, LBP_AL },
+       { 0x1039F, 0x1039F, LBP_BA },
+       { 0x103A0, 0x103CF, LBP_AL },
+       { 0x103D0, 0x103D0, LBP_BA },
+       { 0x103D1, 0x1049D, LBP_AL },
+       { 0x104A0, 0x104A9, LBP_NU },
+       { 0x10500, 0x10855, LBP_AL },
+       { 0x10857, 0x10857, LBP_BA },
+       { 0x10858, 0x1091B, LBP_AL },
+       { 0x1091F, 0x1091F, LBP_BA },
+       { 0x10920, 0x10A00, LBP_AL },
+       { 0x10A01, 0x10A0F, LBP_CM },
+       { 0x10A10, 0x10A33, LBP_AL },
+       { 0x10A38, 0x10A3F, LBP_CM },
+       { 0x10A40, 0x10A47, LBP_AL },
+       { 0x10A50, 0x10A57, LBP_BA },
+       { 0x10A58, 0x10AE4, LBP_AL },
+       { 0x10AE5, 0x10AE6, LBP_CM },
+       { 0x10AEB, 0x10AEF, LBP_AL },
+       { 0x10AF0, 0x10AF5, LBP_BA },
+       { 0x10AF6, 0x10AF6, LBP_IN },
+       { 0x10B00, 0x10B35, LBP_AL },
+       { 0x10B39, 0x10B3F, LBP_BA },
+       { 0x10B40, 0x10E7E, LBP_AL },
+       { 0x11000, 0x11002, LBP_CM },
+       { 0x11003, 0x11037, LBP_AL },
+       { 0x11038, 0x11046, LBP_CM },
+       { 0x11047, 0x11048, LBP_BA },
+       { 0x11049, 0x11065, LBP_AL },
+       { 0x11066, 0x1106F, LBP_NU },
+       { 0x1107F, 0x11082, LBP_CM },
+       { 0x11083, 0x110AF, LBP_AL },
+       { 0x110B0, 0x110BA, LBP_CM },
+       { 0x110BB, 0x110BD, LBP_AL },
+       { 0x110BE, 0x110C1, LBP_BA },
+       { 0x110D0, 0x110E8, LBP_AL },
+       { 0x110F0, 0x110F9, LBP_NU },
+       { 0x11100, 0x11102, LBP_CM },
+       { 0x11103, 0x11126, LBP_AL },
+       { 0x11127, 0x11134, LBP_CM },
+       { 0x11136, 0x1113F, LBP_NU },
+       { 0x11140, 0x11143, LBP_BA },
+       { 0x11150, 0x11172, LBP_AL },
+       { 0x11173, 0x11173, LBP_CM },
+       { 0x11174, 0x11174, LBP_AL },
+       { 0x11175, 0x11175, LBP_BB },
+       { 0x11176, 0x11176, LBP_AL },
+       { 0x11180, 0x11182, LBP_CM },
+       { 0x11183, 0x111B2, LBP_AL },
+       { 0x111B3, 0x111C0, LBP_CM },
+       { 0x111C1, 0x111C4, LBP_AL },
+       { 0x111C5, 0x111C6, LBP_BA },
+       { 0x111C7, 0x111C7, LBP_AL },
+       { 0x111C8, 0x111C8, LBP_BA },
+       { 0x111CD, 0x111CD, LBP_AL },
+       { 0x111D0, 0x111D9, LBP_NU },
+       { 0x111DA, 0x1122B, LBP_AL },
+       { 0x1122C, 0x11237, LBP_CM },
+       { 0x11238, 0x11239, LBP_BA },
+       { 0x1123A, 0x1123A, LBP_AL },
+       { 0x1123B, 0x1123C, LBP_BA },
+       { 0x1123D, 0x112DE, LBP_AL },
+       { 0x112DF, 0x112EA, LBP_CM },
+       { 0x112F0, 0x112F9, LBP_NU },
+       { 0x11301, 0x11303, LBP_CM },
+       { 0x11305, 0x11339, LBP_AL },
+       { 0x1133C, 0x1133C, LBP_CM },
+       { 0x1133D, 0x1133D, LBP_AL },
+       { 0x1133E, 0x11357, LBP_CM },
+       { 0x1135D, 0x11361, LBP_AL },
+       { 0x11362, 0x11374, LBP_CM },
+       { 0x11480, 0x114AF, LBP_AL },
+       { 0x114B0, 0x114C3, LBP_CM },
+       { 0x114C4, 0x114C7, LBP_AL },
+       { 0x114D0, 0x114D9, LBP_NU },
+       { 0x11580, 0x115AE, LBP_AL },
+       { 0x115AF, 0x115C0, LBP_CM },
+       { 0x115C1, 0x115C1, LBP_BB },
+       { 0x115C2, 0x115C3, LBP_BA },
+       { 0x115C4, 0x115C5, LBP_EX },
+       { 0x115C6, 0x115C8, LBP_AL },
+       { 0x115C9, 0x115C9, LBP_BA },
+       { 0x11600, 0x1162F, LBP_AL },
+       { 0x11630, 0x11640, LBP_CM },
+       { 0x11641, 0x11642, LBP_BA },
+       { 0x11643, 0x11644, LBP_AL },
+       { 0x11650, 0x11659, LBP_NU },
+       { 0x11680, 0x116AA, LBP_AL },
+       { 0x116AB, 0x116B7, LBP_CM },
+       { 0x116C0, 0x116C9, LBP_NU },
+       { 0x118A0, 0x118DF, LBP_AL },
+       { 0x118E0, 0x118E9, LBP_NU },
+       { 0x118EA, 0x1246E, LBP_AL },
+       { 0x12470, 0x12474, LBP_BA },
+       { 0x13000, 0x13257, LBP_AL },
+       { 0x13258, 0x1325A, LBP_OP },
+       { 0x1325B, 0x1325D, LBP_CL },
+       { 0x1325E, 0x13281, LBP_AL },
+       { 0x13282, 0x13282, LBP_CL },
+       { 0x13283, 0x13285, LBP_AL },
+       { 0x13286, 0x13286, LBP_OP },
+       { 0x13287, 0x13287, LBP_CL },
+       { 0x13288, 0x13288, LBP_OP },
+       { 0x13289, 0x13289, LBP_CL },
+       { 0x1328A, 0x13378, LBP_AL },
+       { 0x13379, 0x13379, LBP_OP },
+       { 0x1337A, 0x1337B, LBP_CL },
+       { 0x1337C, 0x16A5E, LBP_AL },
+       { 0x16A60, 0x16A69, LBP_NU },
+       { 0x16A6E, 0x16A6F, LBP_BA },
+       { 0x16AD0, 0x16AED, LBP_AL },
+       { 0x16AF0, 0x16AF4, LBP_CM },
+       { 0x16AF5, 0x16AF5, LBP_BA },
+       { 0x16B00, 0x16B2F, LBP_AL },
+       { 0x16B30, 0x16B36, LBP_CM },
+       { 0x16B37, 0x16B39, LBP_BA },
+       { 0x16B3A, 0x16B43, LBP_AL },
+       { 0x16B44, 0x16B44, LBP_BA },
+       { 0x16B45, 0x16B45, LBP_AL },
+       { 0x16B50, 0x16B59, LBP_NU },
+       { 0x16B5B, 0x16F50, LBP_AL },
+       { 0x16F51, 0x16F92, LBP_CM },
+       { 0x16F93, 0x16F9F, LBP_AL },
+       { 0x1B000, 0x1B001, LBP_ID },
+       { 0x1BC00, 0x1BC9C, LBP_AL },
+       { 0x1BC9D, 0x1BC9E, LBP_CM },
+       { 0x1BC9F, 0x1BC9F, LBP_BA },
+       { 0x1BCA0, 0x1BCA3, LBP_CM },
+       { 0x1D000, 0x1D164, LBP_AL },
+       { 0x1D165, 0x1D169, LBP_CM },
+       { 0x1D16A, 0x1D16C, LBP_AL },
+       { 0x1D16D, 0x1D182, LBP_CM },
+       { 0x1D183, 0x1D184, LBP_AL },
+       { 0x1D185, 0x1D18B, LBP_CM },
+       { 0x1D18C, 0x1D1A9, LBP_AL },
+       { 0x1D1AA, 0x1D1AD, LBP_CM },
+       { 0x1D1AE, 0x1D241, LBP_AL },
+       { 0x1D242, 0x1D244, LBP_CM },
+       { 0x1D245, 0x1D7CB, LBP_AL },
+       { 0x1D7CE, 0x1D7FF, LBP_NU },
+       { 0x1E800, 0x1E8CF, LBP_AL },
+       { 0x1E8D0, 0x1E8D6, LBP_CM },
+       { 0x1EE00, 0x1EEF1, LBP_AL },
+       { 0x1F000, 0x1F0F5, LBP_ID },
+       { 0x1F100, 0x1F12D, LBP_AI },
+       { 0x1F12E, 0x1F12E, LBP_AL },
+       { 0x1F130, 0x1F169, LBP_AI },
+       { 0x1F16A, 0x1F16B, LBP_AL },
+       { 0x1F170, 0x1F19A, LBP_AI },
+       { 0x1F1E6, 0x1F1FF, LBP_RI },
+       { 0x1F200, 0x1F39B, LBP_ID },
+       { 0x1F39C, 0x1F39D, LBP_AL },
+       { 0x1F39E, 0x1F3B4, LBP_ID },
+       { 0x1F3B5, 0x1F3B6, LBP_AL },
+       { 0x1F3B7, 0x1F3BB, LBP_ID },
+       { 0x1F3BC, 0x1F3BC, LBP_AL },
+       { 0x1F3BD, 0x1F49F, LBP_ID },
+       { 0x1F4A0, 0x1F4A0, LBP_AL },
+       { 0x1F4A1, 0x1F4A1, LBP_ID },
+       { 0x1F4A2, 0x1F4A2, LBP_AL },
+       { 0x1F4A3, 0x1F4A3, LBP_ID },
+       { 0x1F4A4, 0x1F4A4, LBP_AL },
+       { 0x1F4A5, 0x1F4AE, LBP_ID },
+       { 0x1F4AF, 0x1F4AF, LBP_AL },
+       { 0x1F4B0, 0x1F4B0, LBP_ID },
+       { 0x1F4B1, 0x1F4B2, LBP_AL },
+       { 0x1F4B3, 0x1F4FE, LBP_ID },
+       { 0x1F500, 0x1F506, LBP_AL },
+       { 0x1F507, 0x1F516, LBP_ID },
+       { 0x1F517, 0x1F524, LBP_AL },
+       { 0x1F525, 0x1F531, LBP_ID },
+       { 0x1F532, 0x1F549, LBP_AL },
+       { 0x1F54A, 0x1F5D3, LBP_ID },
+       { 0x1F5D4, 0x1F5DB, LBP_AL },
+       { 0x1F5DC, 0x1F5F3, LBP_ID },
+       { 0x1F5F4, 0x1F5F9, LBP_AL },
+       { 0x1F5FA, 0x1F64F, LBP_ID },
+       { 0x1F650, 0x1F675, LBP_AL },
+       { 0x1F676, 0x1F678, LBP_QU },
+       { 0x1F679, 0x1F67B, LBP_NS },
+       { 0x1F67C, 0x1F67F, LBP_AL },
+       { 0x1F680, 0x1F6F3, LBP_ID },
+       { 0x1F700, 0x1F8AD, LBP_AL },
+       { 0x20000, 0x3FFFD, LBP_ID },
+       { 0xE0001, 0xE01EF, LBP_CM },
+       { 0xF0000, 0x10FFFD, LBP_XX },
+       { 0xFFFFFFFF, 0xFFFFFFFF, LBP_Undefined }
+};
diff --git a/text/dali/internal/libunibreak/linebreakdef.c b/text/dali/internal/libunibreak/linebreakdef.c
new file mode 100644 (file)
index 0000000..3455afd
--- /dev/null
@@ -0,0 +1,139 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2012 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 30, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-30.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreakdef.c
+ *
+ * Definition of language-specific data.
+ *
+ * @version 2.2, 2012/10/06
+ * @author  Wu Yongwei
+ */
+
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+/**
+ * English-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_English[] = {
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * German-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_German[] = {
+    { 0x00AB, 0x00AB, LBP_CL }, /* Left double angle quotation mark: closing */
+    { 0x00BB, 0x00BB, LBP_OP }, /* Right double angle quotation mark: opening */
+    { 0x2018, 0x2018, LBP_CL }, /* Left single quotation mark: closing */
+    { 0x201C, 0x201C, LBP_CL }, /* Left double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_CL }, /* Left single angle quotation mark: closing */
+    { 0x203A, 0x203A, LBP_OP }, /* Right single angle quotation mark: opening */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Spanish-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Spanish[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_OP }, /* Left single angle quotation mark: opening */
+    { 0x203A, 0x203A, LBP_CL }, /* Right single angle quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * French-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_French[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_OP }, /* Left single angle quotation mark: opening */
+    { 0x203A, 0x203A, LBP_CL }, /* Right single angle quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Russian-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Russian[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x201C, 0x201C, LBP_CL }, /* Left double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Chinese-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Chinese[] = {
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x2019, 0x2019, LBP_CL }, /* Right single quotation mark: closing */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Association data of language-specific line breaking properties with
+ * language names.  This is the definition for the static data in this
+ * file.  If you want more flexibility, or do not need the data here,
+ * you may want to redefine \e lb_prop_lang_map in your C source file.
+ */
+struct LineBreakPropertiesLang lb_prop_lang_map[] = {
+    { "en", 2, lb_prop_English },
+    { "de", 2, lb_prop_German },
+    { "es", 2, lb_prop_Spanish },
+    { "fr", 2, lb_prop_French },
+    { "ru", 2, lb_prop_Russian },
+    { "zh", 2, lb_prop_Chinese },
+    { NULL, 0, NULL }
+};
diff --git a/text/dali/internal/libunibreak/linebreakdef.h b/text/dali/internal/libunibreak/linebreakdef.h
new file mode 100644 (file)
index 0000000..d557aba
--- /dev/null
@@ -0,0 +1,174 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2013 Wu Yongwei <wuyongwei at gmail dot com>
+ * Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 30, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-30.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreakdef.h
+ *
+ * Definitions of internal data structures, declarations of global
+ * variables, and function prototypes for the line breaking algorithm.
+ *
+ * @version 2.4, 2013/11/10
+ * @author  Wu Yongwei
+ * @author  Petr Filipsky
+ */
+
+/**
+ * Constant value to mark the end of string.  It is not a valid Unicode
+ * character.
+ */
+#define EOS 0xFFFFFFFF
+
+/**
+ * Line break classes.  This is a direct mapping of Table 1 of Unicode
+ * Standard Annex 14, Revision 26.
+ */
+enum LineBreakClass
+{
+    /* This is used to signal an error condition. */
+    LBP_Undefined,  /**< Undefined */
+
+    /* The following break classes are treated in the pair table. */
+    LBP_OP,         /**< Opening punctuation */
+    LBP_CL,         /**< Closing punctuation */
+    LBP_CP,         /**< Closing parenthesis */
+    LBP_QU,         /**< Ambiguous quotation */
+    LBP_GL,         /**< Glue */
+    LBP_NS,         /**< Non-starters */
+    LBP_EX,         /**< Exclamation/Interrogation */
+    LBP_SY,         /**< Symbols allowing break after */
+    LBP_IS,         /**< Infix separator */
+    LBP_PR,         /**< Prefix */
+    LBP_PO,         /**< Postfix */
+    LBP_NU,         /**< Numeric */
+    LBP_AL,         /**< Alphabetic */
+    LBP_HL,         /**< Hebrew letter */
+    LBP_ID,         /**< Ideographic */
+    LBP_IN,         /**< Inseparable characters */
+    LBP_HY,         /**< Hyphen */
+    LBP_BA,         /**< Break after */
+    LBP_BB,         /**< Break before */
+    LBP_B2,         /**< Break on either side (but not pair) */
+    LBP_ZW,         /**< Zero-width space */
+    LBP_CM,         /**< Combining marks */
+    LBP_WJ,         /**< Word joiner */
+    LBP_H2,         /**< Hangul LV */
+    LBP_H3,         /**< Hangul LVT */
+    LBP_JL,         /**< Hangul L Jamo */
+    LBP_JV,         /**< Hangul V Jamo */
+    LBP_JT,         /**< Hangul T Jamo */
+    LBP_RI,         /**< Regional indicator */
+
+    /* The following break classes are not treated in the pair table */
+    LBP_AI,         /**< Ambiguous (alphabetic or ideograph) */
+    LBP_BK,         /**< Break (mandatory) */
+    LBP_CB,         /**< Contingent break */
+    LBP_CJ,         /**< Conditional Japanese starter */
+    LBP_CR,         /**< Carriage return */
+    LBP_LF,         /**< Line feed */
+    LBP_NL,         /**< Next line */
+    LBP_SA,         /**< South-East Asian */
+    LBP_SG,         /**< Surrogates */
+    LBP_SP,         /**< Space */
+    LBP_XX          /**< Unknown */
+};
+
+/**
+ * Struct for entries of line break properties.  The array of the
+ * entries \e must be sorted.
+ */
+struct LineBreakProperties
+{
+    utf32_t start;              /**< Starting coding point */
+    utf32_t end;                /**< End coding point */
+    enum LineBreakClass prop;   /**< The line breaking property */
+};
+
+/**
+ * Struct for association of language-specific line breaking properties
+ * with language names.
+ */
+struct LineBreakPropertiesLang
+{
+    const char *lang;                   /**< Language name */
+    size_t namelen;                     /**< Length of name to match */
+    struct LineBreakProperties *lbp;    /**< Pointer to associated data */
+};
+
+/**
+ * Context representing internal state of the line breaking algorithm.
+ * This is useful to callers if incremental analysis is wanted.
+ */
+struct LineBreakContext
+{
+    const char *lang;               /**< Language name */
+    struct LineBreakProperties *lbpLang;/**< Pointer to LineBreakProperties */
+    enum LineBreakClass lbcCur;     /**< Breaking class of current codepoint */
+    enum LineBreakClass lbcNew;     /**< Breaking class of next codepoint */
+    enum LineBreakClass lbcLast;    /**< Breaking class of last codepoint */
+};
+
+/**
+ * Abstract function interface for #lb_get_next_char_utf8,
+ * #lb_get_next_char_utf16, and #lb_get_next_char_utf32.
+ */
+typedef utf32_t (*get_next_char_t)(const void *, size_t, size_t *);
+
+/* Declarations */
+extern struct LineBreakProperties lb_prop_default[];
+extern struct LineBreakPropertiesLang lb_prop_lang_map[];
+
+/* Function Prototype */
+utf32_t lb_get_next_char_utf8(const utf8_t *s, size_t len, size_t *ip);
+utf32_t lb_get_next_char_utf16(const utf16_t *s, size_t len, size_t *ip);
+utf32_t lb_get_next_char_utf32(const utf32_t *s, size_t len, size_t *ip);
+void lb_init_break_context(
+        struct LineBreakContext* lbpCtx,
+        utf32_t ch,
+        const char* lang);
+int lb_process_next_char(
+        struct LineBreakContext* lbpCtx,
+        utf32_t ch);
+void set_linebreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char);
diff --git a/text/dali/internal/libunibreak/wordbreak.c b/text/dali/internal/libunibreak/wordbreak.c
new file mode 100644 (file)
index 0000000..e67a1f8
--- /dev/null
@@ -0,0 +1,452 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013 Tom Hacohen <tom at stosb dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 21, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-21.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreak.c
+ *
+ * Implementation of the word breaking algorithm as described in Unicode
+ * Standard Annex 29.
+ *
+ * @version 2.4, 2013/09/28
+ * @author  Tom Hacohen
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+#include "wordbreak.h"
+#include "wordbreakdata.c"
+
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
+
+/**
+ * Initializes the wordbreak internals.  It currently does nothing, but
+ * it may in the future.
+ */
+void init_wordbreak(void)
+{
+}
+
+/**
+ * Gets the word breaking class of a character.
+ *
+ * @param ch   character to check
+ * @param wbp  pointer to the wbp breaking properties array
+ * @param len  size of the wbp array in number of items
+ * @return     the word breaking class if found; \c WBP_Any otherwise
+ */
+static enum WordBreakClass get_char_wb_class(
+        utf32_t ch,
+        struct WordBreakProperties *wbp,
+        size_t len)
+{
+    int min = 0;
+    int max = len - 1;
+    int mid;
+
+    do
+    {
+        mid = (min + max) / 2;
+
+        if (ch < wbp[mid].start)
+            max = mid - 1;
+        else if (ch > wbp[mid].end)
+            min = mid + 1;
+        else
+            return wbp[mid].prop;
+    }
+    while (min <= max);
+
+    return WBP_Any;
+}
+
+/**
+ * Sets the word break types to a specific value in a range.
+ *
+ * It sets the inside chars to #WORDBREAK_INSIDEACHAR and the rest to brkType.
+ * Assumes \a brks is initialized - all the cells with #WORDBREAK_NOBREAK are
+ * cells that we really don't want to break after.
+ *
+ * @param[in]  s             input string
+ * @param[out] brks          breaks array to fill
+ * @param[in]  posStart      start position
+ * @param[in]  posEnd        end position (exclusive)
+ * @param[in]  len           length of the string
+ * @param[in]  brkType       breaks type to use
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+static void set_brks_to(
+        const void *s,
+        char *brks,
+        size_t posStart,
+        size_t posEnd,
+        size_t len,
+        char brkType,
+        get_next_char_t get_next_char)
+{
+    size_t posNext = posStart;
+    while (posNext < posEnd)
+    {
+        utf32_t ch;
+        ch = get_next_char(s, len, &posNext);
+        assert(ch != EOS);
+        for (; posStart < posNext - 1; ++posStart)
+            brks[posStart] = WORDBREAK_INSIDEACHAR;
+        assert(posStart == posNext - 1);
+
+        /* Only set it if we haven't set it not to break before. */
+        if (brks[posStart] != WORDBREAK_NOBREAK)
+            brks[posStart] = brkType;
+        posStart = posNext;
+    }
+}
+
+/* Checks to see if the class is newline, CR, or LF (rules WB3a and b). */
+#define IS_WB3ab(cls) ((cls == WBP_Newline) || (cls == WBP_CR) || \
+                       (cls == WBP_LF))
+
+/**
+ * Sets the word breaking information for a generic input string.
+ *
+ * @param[in]  s             input string
+ * @param[in]  len           length of the input
+ * @param[in]  lang          language of the input
+ * @param[out] brks          pointer to the output breaking data, containing
+ *                           #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                           #WORDBREAK_INSIDEACHAR
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+static void set_wordbreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char)
+{
+    enum WordBreakClass wbcLast = WBP_Undefined;
+    /* wbcSeqStart is the class that started the current sequence.
+     * WBP_Undefined is a special case that means "sot".
+     * This value is the class that is at the start of the current rule
+     * matching sequence. For example, in case of Numeric+MidNum+Numeric
+     * it'll be Numeric all the way.
+     */
+    enum WordBreakClass wbcSeqStart = WBP_Undefined;
+    utf32_t ch;
+    size_t posNext = 0;
+    size_t posCur = 0;
+    size_t posLast = 0;
+
+    /* TODO: Language-specific specialization. */
+    (void) lang;
+
+    /* Init brks. */
+    memset(brks, WORDBREAK_BREAK, len);
+
+    ch = get_next_char(s, len, &posNext);
+
+    while (ch != EOS)
+    {
+        enum WordBreakClass wbcCur;
+        wbcCur = get_char_wb_class(ch, wb_prop_default,
+                                   ARRAY_LEN(wb_prop_default));
+
+        switch (wbcCur)
+        {
+        case WBP_CR:
+            /* WB3b */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_LF:
+            if (wbcSeqStart == WBP_CR) /* WB3 */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+                break;
+            }
+            /* Fall off */
+
+        case WBP_Newline:
+            /* WB3a,3b */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Extend:
+        case WBP_Format:
+            /* WB4 - If not the first char/after a newline (WB3a,3b), skip
+             * this class, set it to be the same as the prev, and mark
+             * brks not to break before them. */
+            if ((wbcSeqStart == WBP_Undefined) || IS_WB3ab(wbcSeqStart))
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+            }
+            else
+            {
+                /* It's surely not the first */
+                brks[posCur - 1] = WORDBREAK_NOBREAK;
+                /* "inherit" the previous class. */
+                wbcCur = wbcLast;
+            }
+            break;
+
+        case WBP_Katakana:
+            if ((wbcSeqStart == WBP_Katakana) || /* WB13 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_ALetter:
+            if ((wbcSeqStart == WBP_ALetter) || /* WB5,6,7 */
+                    (wbcLast == WBP_Numeric) || /* WB10 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_MidNumLet:
+            if ((wbcLast == WBP_ALetter) || /* WB6,7 */
+                    (wbcLast == WBP_Numeric)) /* WB11,12 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_MidLetter:
+            if (wbcLast == WBP_ALetter) /* WB6,7 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_MidNum:
+            if (wbcLast == WBP_Numeric) /* WB11,12 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_Numeric:
+            if ((wbcSeqStart == WBP_Numeric) || /* WB8,11,12 */
+                    (wbcLast == WBP_ALetter) || /* WB9 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_ExtendNumLet:
+            /* WB13a,13b */
+            if ((wbcSeqStart == wbcLast) &&
+                ((wbcLast == WBP_ALetter) ||
+                 (wbcLast == WBP_Numeric) ||
+                 (wbcLast == WBP_Katakana) ||
+                 (wbcLast == WBP_ExtendNumLet)))
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Regional:
+            /* WB13c */
+            if (wbcSeqStart == WBP_Regional)
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Any:
+            /* Allow breaks and reset */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        default:
+            /* Error, should never get here! */
+            assert(0);
+            break;
+        }
+
+        wbcLast = wbcCur;
+        posCur = posNext;
+        ch = get_next_char(s, len, &posNext);
+    }
+
+    /* WB2 */
+    set_brks_to(s, brks, posLast, posNext, len,
+                WORDBREAK_BREAK, get_next_char);
+}
+
+/**
+ * Sets the word breaking information for a UTF-8 input string.
+ *
+ * @param[in]  s     input UTF-8 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf8(
+        const utf8_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf8);
+}
+
+/**
+ * Sets the word breaking information for a UTF-16 input string.
+ *
+ * @param[in]  s     input UTF-16 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf16(
+        const utf16_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf16);
+}
+
+/**
+ * Sets the word breaking information for a UTF-32 input string.
+ *
+ * @param[in]  s     input UTF-32 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf32(
+        const utf32_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)lb_get_next_char_utf32);
+}
diff --git a/text/dali/internal/libunibreak/wordbreak.h b/text/dali/internal/libunibreak/wordbreak.h
new file mode 100644 (file)
index 0000000..cd2bf2c
--- /dev/null
@@ -0,0 +1,76 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013 Tom Hacohen <tom at stosb dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 21, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-21.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreak.h
+ *
+ * Header file for the word breaking (segmentation) algorithm.
+ *
+ * @version 2.3, 2013/09/28
+ * @author  Tom Hacohen
+ */
+
+#ifndef WORDBREAK_H
+#define WORDBREAK_H
+
+#include <stddef.h>
+#include "linebreak.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WORDBREAK_BREAK         0   /**< Break is allowed */
+#define WORDBREAK_NOBREAK       1   /**< No break is allowed */
+#define WORDBREAK_INSIDEACHAR   2   /**< A UTF-8/16 sequence is unfinished */
+
+void init_wordbreak(void);
+void set_wordbreaks_utf8(
+        const utf8_t *s, size_t len, const char* lang, char *brks);
+void set_wordbreaks_utf16(
+        const utf16_t *s, size_t len, const char* lang, char *brks);
+void set_wordbreaks_utf32(
+        const utf32_t *s, size_t len, const char* lang, char *brks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/text/dali/internal/libunibreak/wordbreakdata.c b/text/dali/internal/libunibreak/wordbreakdata.c
new file mode 100644 (file)
index 0000000..fe5afe3
--- /dev/null
@@ -0,0 +1,949 @@
+/* The content of this file is generated from:
+# WordBreakProperty-6.2.0.txt
+# Date: 2012-08-13, 19:12:09 GMT [MD]
+*/
+
+#include "linebreak.h"
+#include "wordbreakdef.h"
+
+static struct WordBreakProperties wb_prop_default[] = {
+       {0x000A, 0x000A, WBP_LF},
+       {0x000B, 0x000C, WBP_Newline},
+       {0x000D, 0x000D, WBP_CR},
+       {0x0027, 0x0027, WBP_MidNumLet},
+       {0x002C, 0x002C, WBP_MidNum},
+       {0x002E, 0x002E, WBP_MidNumLet},
+       {0x0030, 0x0039, WBP_Numeric},
+       {0x003A, 0x003A, WBP_MidLetter},
+       {0x003B, 0x003B, WBP_MidNum},
+       {0x0041, 0x005A, WBP_ALetter},
+       {0x005F, 0x005F, WBP_ExtendNumLet},
+       {0x0061, 0x007A, WBP_ALetter},
+       {0x0085, 0x0085, WBP_Newline},
+       {0x00AA, 0x00AA, WBP_ALetter},
+       {0x00AD, 0x00AD, WBP_Format},
+       {0x00B5, 0x00B5, WBP_ALetter},
+       {0x00B7, 0x00B7, WBP_MidLetter},
+       {0x00BA, 0x00BA, WBP_ALetter},
+       {0x00C0, 0x00D6, WBP_ALetter},
+       {0x00D8, 0x00F6, WBP_ALetter},
+       {0x00F8, 0x01BA, WBP_ALetter},
+       {0x01BB, 0x01BB, WBP_ALetter},
+       {0x01BC, 0x01BF, WBP_ALetter},
+       {0x01C0, 0x01C3, WBP_ALetter},
+       {0x01C4, 0x0293, WBP_ALetter},
+       {0x0294, 0x0294, WBP_ALetter},
+       {0x0295, 0x02AF, WBP_ALetter},
+       {0x02B0, 0x02C1, WBP_ALetter},
+       {0x02C6, 0x02D1, WBP_ALetter},
+       {0x02E0, 0x02E4, WBP_ALetter},
+       {0x02EC, 0x02EC, WBP_ALetter},
+       {0x02EE, 0x02EE, WBP_ALetter},
+       {0x0300, 0x036F, WBP_Extend},
+       {0x0370, 0x0373, WBP_ALetter},
+       {0x0374, 0x0374, WBP_ALetter},
+       {0x0376, 0x0377, WBP_ALetter},
+       {0x037A, 0x037A, WBP_ALetter},
+       {0x037B, 0x037D, WBP_ALetter},
+       {0x037E, 0x037E, WBP_MidNum},
+       {0x0386, 0x0386, WBP_ALetter},
+       {0x0387, 0x0387, WBP_MidLetter},
+       {0x0388, 0x038A, WBP_ALetter},
+       {0x038C, 0x038C, WBP_ALetter},
+       {0x038E, 0x03A1, WBP_ALetter},
+       {0x03A3, 0x03F5, WBP_ALetter},
+       {0x03F7, 0x0481, WBP_ALetter},
+       {0x0483, 0x0487, WBP_Extend},
+       {0x0488, 0x0489, WBP_Extend},
+       {0x048A, 0x0527, WBP_ALetter},
+       {0x0531, 0x0556, WBP_ALetter},
+       {0x0559, 0x0559, WBP_ALetter},
+       {0x0561, 0x0587, WBP_ALetter},
+       {0x0589, 0x0589, WBP_MidNum},
+       {0x0591, 0x05BD, WBP_Extend},
+       {0x05BF, 0x05BF, WBP_Extend},
+       {0x05C1, 0x05C2, WBP_Extend},
+       {0x05C4, 0x05C5, WBP_Extend},
+       {0x05C7, 0x05C7, WBP_Extend},
+       {0x05D0, 0x05EA, WBP_ALetter},
+       {0x05F0, 0x05F2, WBP_ALetter},
+       {0x05F3, 0x05F3, WBP_ALetter},
+       {0x05F4, 0x05F4, WBP_MidLetter},
+       {0x0600, 0x0604, WBP_Format},
+       {0x060C, 0x060D, WBP_MidNum},
+       {0x0610, 0x061A, WBP_Extend},
+       {0x0620, 0x063F, WBP_ALetter},
+       {0x0640, 0x0640, WBP_ALetter},
+       {0x0641, 0x064A, WBP_ALetter},
+       {0x064B, 0x065F, WBP_Extend},
+       {0x0660, 0x0669, WBP_Numeric},
+       {0x066B, 0x066B, WBP_Numeric},
+       {0x066C, 0x066C, WBP_MidNum},
+       {0x066E, 0x066F, WBP_ALetter},
+       {0x0670, 0x0670, WBP_Extend},
+       {0x0671, 0x06D3, WBP_ALetter},
+       {0x06D5, 0x06D5, WBP_ALetter},
+       {0x06D6, 0x06DC, WBP_Extend},
+       {0x06DD, 0x06DD, WBP_Format},
+       {0x06DF, 0x06E4, WBP_Extend},
+       {0x06E5, 0x06E6, WBP_ALetter},
+       {0x06E7, 0x06E8, WBP_Extend},
+       {0x06EA, 0x06ED, WBP_Extend},
+       {0x06EE, 0x06EF, WBP_ALetter},
+       {0x06F0, 0x06F9, WBP_Numeric},
+       {0x06FA, 0x06FC, WBP_ALetter},
+       {0x06FF, 0x06FF, WBP_ALetter},
+       {0x070F, 0x070F, WBP_Format},
+       {0x0710, 0x0710, WBP_ALetter},
+       {0x0711, 0x0711, WBP_Extend},
+       {0x0712, 0x072F, WBP_ALetter},
+       {0x0730, 0x074A, WBP_Extend},
+       {0x074D, 0x07A5, WBP_ALetter},
+       {0x07A6, 0x07B0, WBP_Extend},
+       {0x07B1, 0x07B1, WBP_ALetter},
+       {0x07C0, 0x07C9, WBP_Numeric},
+       {0x07CA, 0x07EA, WBP_ALetter},
+       {0x07EB, 0x07F3, WBP_Extend},
+       {0x07F4, 0x07F5, WBP_ALetter},
+       {0x07F8, 0x07F8, WBP_MidNum},
+       {0x07FA, 0x07FA, WBP_ALetter},
+       {0x0800, 0x0815, WBP_ALetter},
+       {0x0816, 0x0819, WBP_Extend},
+       {0x081A, 0x081A, WBP_ALetter},
+       {0x081B, 0x0823, WBP_Extend},
+       {0x0824, 0x0824, WBP_ALetter},
+       {0x0825, 0x0827, WBP_Extend},
+       {0x0828, 0x0828, WBP_ALetter},
+       {0x0829, 0x082D, WBP_Extend},
+       {0x0840, 0x0858, WBP_ALetter},
+       {0x0859, 0x085B, WBP_Extend},
+       {0x08A0, 0x08A0, WBP_ALetter},
+       {0x08A2, 0x08AC, WBP_ALetter},
+       {0x08E4, 0x08FE, WBP_Extend},
+       {0x0900, 0x0902, WBP_Extend},
+       {0x0903, 0x0903, WBP_Extend},
+       {0x0904, 0x0939, WBP_ALetter},
+       {0x093A, 0x093A, WBP_Extend},
+       {0x093B, 0x093B, WBP_Extend},
+       {0x093C, 0x093C, WBP_Extend},
+       {0x093D, 0x093D, WBP_ALetter},
+       {0x093E, 0x0940, WBP_Extend},
+       {0x0941, 0x0948, WBP_Extend},
+       {0x0949, 0x094C, WBP_Extend},
+       {0x094D, 0x094D, WBP_Extend},
+       {0x094E, 0x094F, WBP_Extend},
+       {0x0950, 0x0950, WBP_ALetter},
+       {0x0951, 0x0957, WBP_Extend},
+       {0x0958, 0x0961, WBP_ALetter},
+       {0x0962, 0x0963, WBP_Extend},
+       {0x0966, 0x096F, WBP_Numeric},
+       {0x0971, 0x0971, WBP_ALetter},
+       {0x0972, 0x0977, WBP_ALetter},
+       {0x0979, 0x097F, WBP_ALetter},
+       {0x0981, 0x0981, WBP_Extend},
+       {0x0982, 0x0983, WBP_Extend},
+       {0x0985, 0x098C, WBP_ALetter},
+       {0x098F, 0x0990, WBP_ALetter},
+       {0x0993, 0x09A8, WBP_ALetter},
+       {0x09AA, 0x09B0, WBP_ALetter},
+       {0x09B2, 0x09B2, WBP_ALetter},
+       {0x09B6, 0x09B9, WBP_ALetter},
+       {0x09BC, 0x09BC, WBP_Extend},
+       {0x09BD, 0x09BD, WBP_ALetter},
+       {0x09BE, 0x09C0, WBP_Extend},
+       {0x09C1, 0x09C4, WBP_Extend},
+       {0x09C7, 0x09C8, WBP_Extend},
+       {0x09CB, 0x09CC, WBP_Extend},
+       {0x09CD, 0x09CD, WBP_Extend},
+       {0x09CE, 0x09CE, WBP_ALetter},
+       {0x09D7, 0x09D7, WBP_Extend},
+       {0x09DC, 0x09DD, WBP_ALetter},
+       {0x09DF, 0x09E1, WBP_ALetter},
+       {0x09E2, 0x09E3, WBP_Extend},
+       {0x09E6, 0x09EF, WBP_Numeric},
+       {0x09F0, 0x09F1, WBP_ALetter},
+       {0x0A01, 0x0A02, WBP_Extend},
+       {0x0A03, 0x0A03, WBP_Extend},
+       {0x0A05, 0x0A0A, WBP_ALetter},
+       {0x0A0F, 0x0A10, WBP_ALetter},
+       {0x0A13, 0x0A28, WBP_ALetter},
+       {0x0A2A, 0x0A30, WBP_ALetter},
+       {0x0A32, 0x0A33, WBP_ALetter},
+       {0x0A35, 0x0A36, WBP_ALetter},
+       {0x0A38, 0x0A39, WBP_ALetter},
+       {0x0A3C, 0x0A3C, WBP_Extend},
+       {0x0A3E, 0x0A40, WBP_Extend},
+       {0x0A41, 0x0A42, WBP_Extend},
+       {0x0A47, 0x0A48, WBP_Extend},
+       {0x0A4B, 0x0A4D, WBP_Extend},
+       {0x0A51, 0x0A51, WBP_Extend},
+       {0x0A59, 0x0A5C, WBP_ALetter},
+       {0x0A5E, 0x0A5E, WBP_ALetter},
+       {0x0A66, 0x0A6F, WBP_Numeric},
+       {0x0A70, 0x0A71, WBP_Extend},
+       {0x0A72, 0x0A74, WBP_ALetter},
+       {0x0A75, 0x0A75, WBP_Extend},
+       {0x0A81, 0x0A82, WBP_Extend},
+       {0x0A83, 0x0A83, WBP_Extend},
+       {0x0A85, 0x0A8D, WBP_ALetter},
+       {0x0A8F, 0x0A91, WBP_ALetter},
+       {0x0A93, 0x0AA8, WBP_ALetter},
+       {0x0AAA, 0x0AB0, WBP_ALetter},
+       {0x0AB2, 0x0AB3, WBP_ALetter},
+       {0x0AB5, 0x0AB9, WBP_ALetter},
+       {0x0ABC, 0x0ABC, WBP_Extend},
+       {0x0ABD, 0x0ABD, WBP_ALetter},
+       {0x0ABE, 0x0AC0, WBP_Extend},
+       {0x0AC1, 0x0AC5, WBP_Extend},
+       {0x0AC7, 0x0AC8, WBP_Extend},
+       {0x0AC9, 0x0AC9, WBP_Extend},
+       {0x0ACB, 0x0ACC, WBP_Extend},
+       {0x0ACD, 0x0ACD, WBP_Extend},
+       {0x0AD0, 0x0AD0, WBP_ALetter},
+       {0x0AE0, 0x0AE1, WBP_ALetter},
+       {0x0AE2, 0x0AE3, WBP_Extend},
+       {0x0AE6, 0x0AEF, WBP_Numeric},
+       {0x0B01, 0x0B01, WBP_Extend},
+       {0x0B02, 0x0B03, WBP_Extend},
+       {0x0B05, 0x0B0C, WBP_ALetter},
+       {0x0B0F, 0x0B10, WBP_ALetter},
+       {0x0B13, 0x0B28, WBP_ALetter},
+       {0x0B2A, 0x0B30, WBP_ALetter},
+       {0x0B32, 0x0B33, WBP_ALetter},
+       {0x0B35, 0x0B39, WBP_ALetter},
+       {0x0B3C, 0x0B3C, WBP_Extend},
+       {0x0B3D, 0x0B3D, WBP_ALetter},
+       {0x0B3E, 0x0B3E, WBP_Extend},
+       {0x0B3F, 0x0B3F, WBP_Extend},
+       {0x0B40, 0x0B40, WBP_Extend},
+       {0x0B41, 0x0B44, WBP_Extend},
+       {0x0B47, 0x0B48, WBP_Extend},
+       {0x0B4B, 0x0B4C, WBP_Extend},
+       {0x0B4D, 0x0B4D, WBP_Extend},
+       {0x0B56, 0x0B56, WBP_Extend},
+       {0x0B57, 0x0B57, WBP_Extend},
+       {0x0B5C, 0x0B5D, WBP_ALetter},
+       {0x0B5F, 0x0B61, WBP_ALetter},
+       {0x0B62, 0x0B63, WBP_Extend},
+       {0x0B66, 0x0B6F, WBP_Numeric},
+       {0x0B71, 0x0B71, WBP_ALetter},
+       {0x0B82, 0x0B82, WBP_Extend},
+       {0x0B83, 0x0B83, WBP_ALetter},
+       {0x0B85, 0x0B8A, WBP_ALetter},
+       {0x0B8E, 0x0B90, WBP_ALetter},
+       {0x0B92, 0x0B95, WBP_ALetter},
+       {0x0B99, 0x0B9A, WBP_ALetter},
+       {0x0B9C, 0x0B9C, WBP_ALetter},
+       {0x0B9E, 0x0B9F, WBP_ALetter},
+       {0x0BA3, 0x0BA4, WBP_ALetter},
+       {0x0BA8, 0x0BAA, WBP_ALetter},
+       {0x0BAE, 0x0BB9, WBP_ALetter},
+       {0x0BBE, 0x0BBF, WBP_Extend},
+       {0x0BC0, 0x0BC0, WBP_Extend},
+       {0x0BC1, 0x0BC2, WBP_Extend},
+       {0x0BC6, 0x0BC8, WBP_Extend},
+       {0x0BCA, 0x0BCC, WBP_Extend},
+       {0x0BCD, 0x0BCD, WBP_Extend},
+       {0x0BD0, 0x0BD0, WBP_ALetter},
+       {0x0BD7, 0x0BD7, WBP_Extend},
+       {0x0BE6, 0x0BEF, WBP_Numeric},
+       {0x0C01, 0x0C03, WBP_Extend},
+       {0x0C05, 0x0C0C, WBP_ALetter},
+       {0x0C0E, 0x0C10, WBP_ALetter},
+       {0x0C12, 0x0C28, WBP_ALetter},
+       {0x0C2A, 0x0C33, WBP_ALetter},
+       {0x0C35, 0x0C39, WBP_ALetter},
+       {0x0C3D, 0x0C3D, WBP_ALetter},
+       {0x0C3E, 0x0C40, WBP_Extend},
+       {0x0C41, 0x0C44, WBP_Extend},
+       {0x0C46, 0x0C48, WBP_Extend},
+       {0x0C4A, 0x0C4D, WBP_Extend},
+       {0x0C55, 0x0C56, WBP_Extend},
+       {0x0C58, 0x0C59, WBP_ALetter},
+       {0x0C60, 0x0C61, WBP_ALetter},
+       {0x0C62, 0x0C63, WBP_Extend},
+       {0x0C66, 0x0C6F, WBP_Numeric},
+       {0x0C82, 0x0C83, WBP_Extend},
+       {0x0C85, 0x0C8C, WBP_ALetter},
+       {0x0C8E, 0x0C90, WBP_ALetter},
+       {0x0C92, 0x0CA8, WBP_ALetter},
+       {0x0CAA, 0x0CB3, WBP_ALetter},
+       {0x0CB5, 0x0CB9, WBP_ALetter},
+       {0x0CBC, 0x0CBC, WBP_Extend},
+       {0x0CBD, 0x0CBD, WBP_ALetter},
+       {0x0CBE, 0x0CBE, WBP_Extend},
+       {0x0CBF, 0x0CBF, WBP_Extend},
+       {0x0CC0, 0x0CC4, WBP_Extend},
+       {0x0CC6, 0x0CC6, WBP_Extend},
+       {0x0CC7, 0x0CC8, WBP_Extend},
+       {0x0CCA, 0x0CCB, WBP_Extend},
+       {0x0CCC, 0x0CCD, WBP_Extend},
+       {0x0CD5, 0x0CD6, WBP_Extend},
+       {0x0CDE, 0x0CDE, WBP_ALetter},
+       {0x0CE0, 0x0CE1, WBP_ALetter},
+       {0x0CE2, 0x0CE3, WBP_Extend},
+       {0x0CE6, 0x0CEF, WBP_Numeric},
+       {0x0CF1, 0x0CF2, WBP_ALetter},
+       {0x0D02, 0x0D03, WBP_Extend},
+       {0x0D05, 0x0D0C, WBP_ALetter},
+       {0x0D0E, 0x0D10, WBP_ALetter},
+       {0x0D12, 0x0D3A, WBP_ALetter},
+       {0x0D3D, 0x0D3D, WBP_ALetter},
+       {0x0D3E, 0x0D40, WBP_Extend},
+       {0x0D41, 0x0D44, WBP_Extend},
+       {0x0D46, 0x0D48, WBP_Extend},
+       {0x0D4A, 0x0D4C, WBP_Extend},
+       {0x0D4D, 0x0D4D, WBP_Extend},
+       {0x0D4E, 0x0D4E, WBP_ALetter},
+       {0x0D57, 0x0D57, WBP_Extend},
+       {0x0D60, 0x0D61, WBP_ALetter},
+       {0x0D62, 0x0D63, WBP_Extend},
+       {0x0D66, 0x0D6F, WBP_Numeric},
+       {0x0D7A, 0x0D7F, WBP_ALetter},
+       {0x0D82, 0x0D83, WBP_Extend},
+       {0x0D85, 0x0D96, WBP_ALetter},
+       {0x0D9A, 0x0DB1, WBP_ALetter},
+       {0x0DB3, 0x0DBB, WBP_ALetter},
+       {0x0DBD, 0x0DBD, WBP_ALetter},
+       {0x0DC0, 0x0DC6, WBP_ALetter},
+       {0x0DCA, 0x0DCA, WBP_Extend},
+       {0x0DCF, 0x0DD1, WBP_Extend},
+       {0x0DD2, 0x0DD4, WBP_Extend},
+       {0x0DD6, 0x0DD6, WBP_Extend},
+       {0x0DD8, 0x0DDF, WBP_Extend},
+       {0x0DF2, 0x0DF3, WBP_Extend},
+       {0x0E31, 0x0E31, WBP_Extend},
+       {0x0E34, 0x0E3A, WBP_Extend},
+       {0x0E47, 0x0E4E, WBP_Extend},
+       {0x0E50, 0x0E59, WBP_Numeric},
+       {0x0EB1, 0x0EB1, WBP_Extend},
+       {0x0EB4, 0x0EB9, WBP_Extend},
+       {0x0EBB, 0x0EBC, WBP_Extend},
+       {0x0EC8, 0x0ECD, WBP_Extend},
+       {0x0ED0, 0x0ED9, WBP_Numeric},
+       {0x0F00, 0x0F00, WBP_ALetter},
+       {0x0F18, 0x0F19, WBP_Extend},
+       {0x0F20, 0x0F29, WBP_Numeric},
+       {0x0F35, 0x0F35, WBP_Extend},
+       {0x0F37, 0x0F37, WBP_Extend},
+       {0x0F39, 0x0F39, WBP_Extend},
+       {0x0F3E, 0x0F3F, WBP_Extend},
+       {0x0F40, 0x0F47, WBP_ALetter},
+       {0x0F49, 0x0F6C, WBP_ALetter},
+       {0x0F71, 0x0F7E, WBP_Extend},
+       {0x0F7F, 0x0F7F, WBP_Extend},
+       {0x0F80, 0x0F84, WBP_Extend},
+       {0x0F86, 0x0F87, WBP_Extend},
+       {0x0F88, 0x0F8C, WBP_ALetter},
+       {0x0F8D, 0x0F97, WBP_Extend},
+       {0x0F99, 0x0FBC, WBP_Extend},
+       {0x0FC6, 0x0FC6, WBP_Extend},
+       {0x102B, 0x102C, WBP_Extend},
+       {0x102D, 0x1030, WBP_Extend},
+       {0x1031, 0x1031, WBP_Extend},
+       {0x1032, 0x1037, WBP_Extend},
+       {0x1038, 0x1038, WBP_Extend},
+       {0x1039, 0x103A, WBP_Extend},
+       {0x103B, 0x103C, WBP_Extend},
+       {0x103D, 0x103E, WBP_Extend},
+       {0x1040, 0x1049, WBP_Numeric},
+       {0x1056, 0x1057, WBP_Extend},
+       {0x1058, 0x1059, WBP_Extend},
+       {0x105E, 0x1060, WBP_Extend},
+       {0x1062, 0x1064, WBP_Extend},
+       {0x1067, 0x106D, WBP_Extend},
+       {0x1071, 0x1074, WBP_Extend},
+       {0x1082, 0x1082, WBP_Extend},
+       {0x1083, 0x1084, WBP_Extend},
+       {0x1085, 0x1086, WBP_Extend},
+       {0x1087, 0x108C, WBP_Extend},
+       {0x108D, 0x108D, WBP_Extend},
+       {0x108F, 0x108F, WBP_Extend},
+       {0x1090, 0x1099, WBP_Numeric},
+       {0x109A, 0x109C, WBP_Extend},
+       {0x109D, 0x109D, WBP_Extend},
+       {0x10A0, 0x10C5, WBP_ALetter},
+       {0x10C7, 0x10C7, WBP_ALetter},
+       {0x10CD, 0x10CD, WBP_ALetter},
+       {0x10D0, 0x10FA, WBP_ALetter},
+       {0x10FC, 0x10FC, WBP_ALetter},
+       {0x10FD, 0x1248, WBP_ALetter},
+       {0x124A, 0x124D, WBP_ALetter},
+       {0x1250, 0x1256, WBP_ALetter},
+       {0x1258, 0x1258, WBP_ALetter},
+       {0x125A, 0x125D, WBP_ALetter},
+       {0x1260, 0x1288, WBP_ALetter},
+       {0x128A, 0x128D, WBP_ALetter},
+       {0x1290, 0x12B0, WBP_ALetter},
+       {0x12B2, 0x12B5, WBP_ALetter},
+       {0x12B8, 0x12BE, WBP_ALetter},
+       {0x12C0, 0x12C0, WBP_ALetter},
+       {0x12C2, 0x12C5, WBP_ALetter},
+       {0x12C8, 0x12D6, WBP_ALetter},
+       {0x12D8, 0x1310, WBP_ALetter},
+       {0x1312, 0x1315, WBP_ALetter},
+       {0x1318, 0x135A, WBP_ALetter},
+       {0x135D, 0x135F, WBP_Extend},
+       {0x1380, 0x138F, WBP_ALetter},
+       {0x13A0, 0x13F4, WBP_ALetter},
+       {0x1401, 0x166C, WBP_ALetter},
+       {0x166F, 0x167F, WBP_ALetter},
+       {0x1681, 0x169A, WBP_ALetter},
+       {0x16A0, 0x16EA, WBP_ALetter},
+       {0x16EE, 0x16F0, WBP_ALetter},
+       {0x1700, 0x170C, WBP_ALetter},
+       {0x170E, 0x1711, WBP_ALetter},
+       {0x1712, 0x1714, WBP_Extend},
+       {0x1720, 0x1731, WBP_ALetter},
+       {0x1732, 0x1734, WBP_Extend},
+       {0x1740, 0x1751, WBP_ALetter},
+       {0x1752, 0x1753, WBP_Extend},
+       {0x1760, 0x176C, WBP_ALetter},
+       {0x176E, 0x1770, WBP_ALetter},
+       {0x1772, 0x1773, WBP_Extend},
+       {0x17B4, 0x17B5, WBP_Extend},
+       {0x17B6, 0x17B6, WBP_Extend},
+       {0x17B7, 0x17BD, WBP_Extend},
+       {0x17BE, 0x17C5, WBP_Extend},
+       {0x17C6, 0x17C6, WBP_Extend},
+       {0x17C7, 0x17C8, WBP_Extend},
+       {0x17C9, 0x17D3, WBP_Extend},
+       {0x17DD, 0x17DD, WBP_Extend},
+       {0x17E0, 0x17E9, WBP_Numeric},
+       {0x180B, 0x180D, WBP_Extend},
+       {0x1810, 0x1819, WBP_Numeric},
+       {0x1820, 0x1842, WBP_ALetter},
+       {0x1843, 0x1843, WBP_ALetter},
+       {0x1844, 0x1877, WBP_ALetter},
+       {0x1880, 0x18A8, WBP_ALetter},
+       {0x18A9, 0x18A9, WBP_Extend},
+       {0x18AA, 0x18AA, WBP_ALetter},
+       {0x18B0, 0x18F5, WBP_ALetter},
+       {0x1900, 0x191C, WBP_ALetter},
+       {0x1920, 0x1922, WBP_Extend},
+       {0x1923, 0x1926, WBP_Extend},
+       {0x1927, 0x1928, WBP_Extend},
+       {0x1929, 0x192B, WBP_Extend},
+       {0x1930, 0x1931, WBP_Extend},
+       {0x1932, 0x1932, WBP_Extend},
+       {0x1933, 0x1938, WBP_Extend},
+       {0x1939, 0x193B, WBP_Extend},
+       {0x1946, 0x194F, WBP_Numeric},
+       {0x19B0, 0x19C0, WBP_Extend},
+       {0x19C8, 0x19C9, WBP_Extend},
+       {0x19D0, 0x19D9, WBP_Numeric},
+       {0x1A00, 0x1A16, WBP_ALetter},
+       {0x1A17, 0x1A18, WBP_Extend},
+       {0x1A19, 0x1A1B, WBP_Extend},
+       {0x1A55, 0x1A55, WBP_Extend},
+       {0x1A56, 0x1A56, WBP_Extend},
+       {0x1A57, 0x1A57, WBP_Extend},
+       {0x1A58, 0x1A5E, WBP_Extend},
+       {0x1A60, 0x1A60, WBP_Extend},
+       {0x1A61, 0x1A61, WBP_Extend},
+       {0x1A62, 0x1A62, WBP_Extend},
+       {0x1A63, 0x1A64, WBP_Extend},
+       {0x1A65, 0x1A6C, WBP_Extend},
+       {0x1A6D, 0x1A72, WBP_Extend},
+       {0x1A73, 0x1A7C, WBP_Extend},
+       {0x1A7F, 0x1A7F, WBP_Extend},
+       {0x1A80, 0x1A89, WBP_Numeric},
+       {0x1A90, 0x1A99, WBP_Numeric},
+       {0x1B00, 0x1B03, WBP_Extend},
+       {0x1B04, 0x1B04, WBP_Extend},
+       {0x1B05, 0x1B33, WBP_ALetter},
+       {0x1B34, 0x1B34, WBP_Extend},
+       {0x1B35, 0x1B35, WBP_Extend},
+       {0x1B36, 0x1B3A, WBP_Extend},
+       {0x1B3B, 0x1B3B, WBP_Extend},
+       {0x1B3C, 0x1B3C, WBP_Extend},
+       {0x1B3D, 0x1B41, WBP_Extend},
+       {0x1B42, 0x1B42, WBP_Extend},
+       {0x1B43, 0x1B44, WBP_Extend},
+       {0x1B45, 0x1B4B, WBP_ALetter},
+       {0x1B50, 0x1B59, WBP_Numeric},
+       {0x1B6B, 0x1B73, WBP_Extend},
+       {0x1B80, 0x1B81, WBP_Extend},
+       {0x1B82, 0x1B82, WBP_Extend},
+       {0x1B83, 0x1BA0, WBP_ALetter},
+       {0x1BA1, 0x1BA1, WBP_Extend},
+       {0x1BA2, 0x1BA5, WBP_Extend},
+       {0x1BA6, 0x1BA7, WBP_Extend},
+       {0x1BA8, 0x1BA9, WBP_Extend},
+       {0x1BAA, 0x1BAA, WBP_Extend},
+       {0x1BAB, 0x1BAB, WBP_Extend},
+       {0x1BAC, 0x1BAD, WBP_Extend},
+       {0x1BAE, 0x1BAF, WBP_ALetter},
+       {0x1BB0, 0x1BB9, WBP_Numeric},
+       {0x1BBA, 0x1BE5, WBP_ALetter},
+       {0x1BE6, 0x1BE6, WBP_Extend},
+       {0x1BE7, 0x1BE7, WBP_Extend},
+       {0x1BE8, 0x1BE9, WBP_Extend},
+       {0x1BEA, 0x1BEC, WBP_Extend},
+       {0x1BED, 0x1BED, WBP_Extend},
+       {0x1BEE, 0x1BEE, WBP_Extend},
+       {0x1BEF, 0x1BF1, WBP_Extend},
+       {0x1BF2, 0x1BF3, WBP_Extend},
+       {0x1C00, 0x1C23, WBP_ALetter},
+       {0x1C24, 0x1C2B, WBP_Extend},
+       {0x1C2C, 0x1C33, WBP_Extend},
+       {0x1C34, 0x1C35, WBP_Extend},
+       {0x1C36, 0x1C37, WBP_Extend},
+       {0x1C40, 0x1C49, WBP_Numeric},
+       {0x1C4D, 0x1C4F, WBP_ALetter},
+       {0x1C50, 0x1C59, WBP_Numeric},
+       {0x1C5A, 0x1C77, WBP_ALetter},
+       {0x1C78, 0x1C7D, WBP_ALetter},
+       {0x1CD0, 0x1CD2, WBP_Extend},
+       {0x1CD4, 0x1CE0, WBP_Extend},
+       {0x1CE1, 0x1CE1, WBP_Extend},
+       {0x1CE2, 0x1CE8, WBP_Extend},
+       {0x1CE9, 0x1CEC, WBP_ALetter},
+       {0x1CED, 0x1CED, WBP_Extend},
+       {0x1CEE, 0x1CF1, WBP_ALetter},
+       {0x1CF2, 0x1CF3, WBP_Extend},
+       {0x1CF4, 0x1CF4, WBP_Extend},
+       {0x1CF5, 0x1CF6, WBP_ALetter},
+       {0x1D00, 0x1D2B, WBP_ALetter},
+       {0x1D2C, 0x1D6A, WBP_ALetter},
+       {0x1D6B, 0x1D77, WBP_ALetter},
+       {0x1D78, 0x1D78, WBP_ALetter},
+       {0x1D79, 0x1D9A, WBP_ALetter},
+       {0x1D9B, 0x1DBF, WBP_ALetter},
+       {0x1DC0, 0x1DE6, WBP_Extend},
+       {0x1DFC, 0x1DFF, WBP_Extend},
+       {0x1E00, 0x1F15, WBP_ALetter},
+       {0x1F18, 0x1F1D, WBP_ALetter},
+       {0x1F20, 0x1F45, WBP_ALetter},
+       {0x1F48, 0x1F4D, WBP_ALetter},
+       {0x1F50, 0x1F57, WBP_ALetter},
+       {0x1F59, 0x1F59, WBP_ALetter},
+       {0x1F5B, 0x1F5B, WBP_ALetter},
+       {0x1F5D, 0x1F5D, WBP_ALetter},
+       {0x1F5F, 0x1F7D, WBP_ALetter},
+       {0x1F80, 0x1FB4, WBP_ALetter},
+       {0x1FB6, 0x1FBC, WBP_ALetter},
+       {0x1FBE, 0x1FBE, WBP_ALetter},
+       {0x1FC2, 0x1FC4, WBP_ALetter},
+       {0x1FC6, 0x1FCC, WBP_ALetter},
+       {0x1FD0, 0x1FD3, WBP_ALetter},
+       {0x1FD6, 0x1FDB, WBP_ALetter},
+       {0x1FE0, 0x1FEC, WBP_ALetter},
+       {0x1FF2, 0x1FF4, WBP_ALetter},
+       {0x1FF6, 0x1FFC, WBP_ALetter},
+       {0x200C, 0x200D, WBP_Extend},
+       {0x200E, 0x200F, WBP_Format},
+       {0x2018, 0x2018, WBP_MidNumLet},
+       {0x2019, 0x2019, WBP_MidNumLet},
+       {0x2024, 0x2024, WBP_MidNumLet},
+       {0x2027, 0x2027, WBP_MidLetter},
+       {0x2028, 0x2028, WBP_Newline},
+       {0x2029, 0x2029, WBP_Newline},
+       {0x202A, 0x202E, WBP_Format},
+       {0x203F, 0x2040, WBP_ExtendNumLet},
+       {0x2044, 0x2044, WBP_MidNum},
+       {0x2054, 0x2054, WBP_ExtendNumLet},
+       {0x2060, 0x2064, WBP_Format},
+       {0x206A, 0x206F, WBP_Format},
+       {0x2071, 0x2071, WBP_ALetter},
+       {0x207F, 0x207F, WBP_ALetter},
+       {0x2090, 0x209C, WBP_ALetter},
+       {0x20D0, 0x20DC, WBP_Extend},
+       {0x20DD, 0x20E0, WBP_Extend},
+       {0x20E1, 0x20E1, WBP_Extend},
+       {0x20E2, 0x20E4, WBP_Extend},
+       {0x20E5, 0x20F0, WBP_Extend},
+       {0x2102, 0x2102, WBP_ALetter},
+       {0x2107, 0x2107, WBP_ALetter},
+       {0x210A, 0x2113, WBP_ALetter},
+       {0x2115, 0x2115, WBP_ALetter},
+       {0x2119, 0x211D, WBP_ALetter},
+       {0x2124, 0x2124, WBP_ALetter},
+       {0x2126, 0x2126, WBP_ALetter},
+       {0x2128, 0x2128, WBP_ALetter},
+       {0x212A, 0x212D, WBP_ALetter},
+       {0x212F, 0x2134, WBP_ALetter},
+       {0x2135, 0x2138, WBP_ALetter},
+       {0x2139, 0x2139, WBP_ALetter},
+       {0x213C, 0x213F, WBP_ALetter},
+       {0x2145, 0x2149, WBP_ALetter},
+       {0x214E, 0x214E, WBP_ALetter},
+       {0x2160, 0x2182, WBP_ALetter},
+       {0x2183, 0x2184, WBP_ALetter},
+       {0x2185, 0x2188, WBP_ALetter},
+       {0x24B6, 0x24E9, WBP_ALetter},
+       {0x2C00, 0x2C2E, WBP_ALetter},
+       {0x2C30, 0x2C5E, WBP_ALetter},
+       {0x2C60, 0x2C7B, WBP_ALetter},
+       {0x2C7C, 0x2C7D, WBP_ALetter},
+       {0x2C7E, 0x2CE4, WBP_ALetter},
+       {0x2CEB, 0x2CEE, WBP_ALetter},
+       {0x2CEF, 0x2CF1, WBP_Extend},
+       {0x2CF2, 0x2CF3, WBP_ALetter},
+       {0x2D00, 0x2D25, WBP_ALetter},
+       {0x2D27, 0x2D27, WBP_ALetter},
+       {0x2D2D, 0x2D2D, WBP_ALetter},
+       {0x2D30, 0x2D67, WBP_ALetter},
+       {0x2D6F, 0x2D6F, WBP_ALetter},
+       {0x2D7F, 0x2D7F, WBP_Extend},
+       {0x2D80, 0x2D96, WBP_ALetter},
+       {0x2DA0, 0x2DA6, WBP_ALetter},
+       {0x2DA8, 0x2DAE, WBP_ALetter},
+       {0x2DB0, 0x2DB6, WBP_ALetter},
+       {0x2DB8, 0x2DBE, WBP_ALetter},
+       {0x2DC0, 0x2DC6, WBP_ALetter},
+       {0x2DC8, 0x2DCE, WBP_ALetter},
+       {0x2DD0, 0x2DD6, WBP_ALetter},
+       {0x2DD8, 0x2DDE, WBP_ALetter},
+       {0x2DE0, 0x2DFF, WBP_Extend},
+       {0x2E2F, 0x2E2F, WBP_ALetter},
+       {0x3005, 0x3005, WBP_ALetter},
+       {0x302A, 0x302D, WBP_Extend},
+       {0x302E, 0x302F, WBP_Extend},
+       {0x3031, 0x3035, WBP_Katakana},
+       {0x303B, 0x303B, WBP_ALetter},
+       {0x303C, 0x303C, WBP_ALetter},
+       {0x3099, 0x309A, WBP_Extend},
+       {0x309B, 0x309C, WBP_Katakana},
+       {0x30A0, 0x30A0, WBP_Katakana},
+       {0x30A1, 0x30FA, WBP_Katakana},
+       {0x30FC, 0x30FE, WBP_Katakana},
+       {0x30FF, 0x30FF, WBP_Katakana},
+       {0x3105, 0x312D, WBP_ALetter},
+       {0x3131, 0x318E, WBP_ALetter},
+       {0x31A0, 0x31BA, WBP_ALetter},
+       {0x31F0, 0x31FF, WBP_Katakana},
+       {0x32D0, 0x32FE, WBP_Katakana},
+       {0x3300, 0x3357, WBP_Katakana},
+       {0xA000, 0xA014, WBP_ALetter},
+       {0xA015, 0xA015, WBP_ALetter},
+       {0xA016, 0xA48C, WBP_ALetter},
+       {0xA4D0, 0xA4F7, WBP_ALetter},
+       {0xA4F8, 0xA4FD, WBP_ALetter},
+       {0xA500, 0xA60B, WBP_ALetter},
+       {0xA60C, 0xA60C, WBP_ALetter},
+       {0xA610, 0xA61F, WBP_ALetter},
+       {0xA620, 0xA629, WBP_Numeric},
+       {0xA62A, 0xA62B, WBP_ALetter},
+       {0xA640, 0xA66D, WBP_ALetter},
+       {0xA66E, 0xA66E, WBP_ALetter},
+       {0xA66F, 0xA66F, WBP_Extend},
+       {0xA670, 0xA672, WBP_Extend},
+       {0xA674, 0xA67D, WBP_Extend},
+       {0xA67F, 0xA67F, WBP_ALetter},
+       {0xA680, 0xA697, WBP_ALetter},
+       {0xA69F, 0xA69F, WBP_Extend},
+       {0xA6A0, 0xA6E5, WBP_ALetter},
+       {0xA6E6, 0xA6EF, WBP_ALetter},
+       {0xA6F0, 0xA6F1, WBP_Extend},
+       {0xA717, 0xA71F, WBP_ALetter},
+       {0xA722, 0xA76F, WBP_ALetter},
+       {0xA770, 0xA770, WBP_ALetter},
+       {0xA771, 0xA787, WBP_ALetter},
+       {0xA788, 0xA788, WBP_ALetter},
+       {0xA78B, 0xA78E, WBP_ALetter},
+       {0xA790, 0xA793, WBP_ALetter},
+       {0xA7A0, 0xA7AA, WBP_ALetter},
+       {0xA7F8, 0xA7F9, WBP_ALetter},
+       {0xA7FA, 0xA7FA, WBP_ALetter},
+       {0xA7FB, 0xA801, WBP_ALetter},
+       {0xA802, 0xA802, WBP_Extend},
+       {0xA803, 0xA805, WBP_ALetter},
+       {0xA806, 0xA806, WBP_Extend},
+       {0xA807, 0xA80A, WBP_ALetter},
+       {0xA80B, 0xA80B, WBP_Extend},
+       {0xA80C, 0xA822, WBP_ALetter},
+       {0xA823, 0xA824, WBP_Extend},
+       {0xA825, 0xA826, WBP_Extend},
+       {0xA827, 0xA827, WBP_Extend},
+       {0xA840, 0xA873, WBP_ALetter},
+       {0xA880, 0xA881, WBP_Extend},
+       {0xA882, 0xA8B3, WBP_ALetter},
+       {0xA8B4, 0xA8C3, WBP_Extend},
+       {0xA8C4, 0xA8C4, WBP_Extend},
+       {0xA8D0, 0xA8D9, WBP_Numeric},
+       {0xA8E0, 0xA8F1, WBP_Extend},
+       {0xA8F2, 0xA8F7, WBP_ALetter},
+       {0xA8FB, 0xA8FB, WBP_ALetter},
+       {0xA900, 0xA909, WBP_Numeric},
+       {0xA90A, 0xA925, WBP_ALetter},
+       {0xA926, 0xA92D, WBP_Extend},
+       {0xA930, 0xA946, WBP_ALetter},
+       {0xA947, 0xA951, WBP_Extend},
+       {0xA952, 0xA953, WBP_Extend},
+       {0xA960, 0xA97C, WBP_ALetter},
+       {0xA980, 0xA982, WBP_Extend},
+       {0xA983, 0xA983, WBP_Extend},
+       {0xA984, 0xA9B2, WBP_ALetter},
+       {0xA9B3, 0xA9B3, WBP_Extend},
+       {0xA9B4, 0xA9B5, WBP_Extend},
+       {0xA9B6, 0xA9B9, WBP_Extend},
+       {0xA9BA, 0xA9BB, WBP_Extend},
+       {0xA9BC, 0xA9BC, WBP_Extend},
+       {0xA9BD, 0xA9C0, WBP_Extend},
+       {0xA9CF, 0xA9CF, WBP_ALetter},
+       {0xA9D0, 0xA9D9, WBP_Numeric},
+       {0xAA00, 0xAA28, WBP_ALetter},
+       {0xAA29, 0xAA2E, WBP_Extend},
+       {0xAA2F, 0xAA30, WBP_Extend},
+       {0xAA31, 0xAA32, WBP_Extend},
+       {0xAA33, 0xAA34, WBP_Extend},
+       {0xAA35, 0xAA36, WBP_Extend},
+       {0xAA40, 0xAA42, WBP_ALetter},
+       {0xAA43, 0xAA43, WBP_Extend},
+       {0xAA44, 0xAA4B, WBP_ALetter},
+       {0xAA4C, 0xAA4C, WBP_Extend},
+       {0xAA4D, 0xAA4D, WBP_Extend},
+       {0xAA50, 0xAA59, WBP_Numeric},
+       {0xAA7B, 0xAA7B, WBP_Extend},
+       {0xAAB0, 0xAAB0, WBP_Extend},
+       {0xAAB2, 0xAAB4, WBP_Extend},
+       {0xAAB7, 0xAAB8, WBP_Extend},
+       {0xAABE, 0xAABF, WBP_Extend},
+       {0xAAC1, 0xAAC1, WBP_Extend},
+       {0xAAE0, 0xAAEA, WBP_ALetter},
+       {0xAAEB, 0xAAEB, WBP_Extend},
+       {0xAAEC, 0xAAED, WBP_Extend},
+       {0xAAEE, 0xAAEF, WBP_Extend},
+       {0xAAF2, 0xAAF2, WBP_ALetter},
+       {0xAAF3, 0xAAF4, WBP_ALetter},
+       {0xAAF5, 0xAAF5, WBP_Extend},
+       {0xAAF6, 0xAAF6, WBP_Extend},
+       {0xAB01, 0xAB06, WBP_ALetter},
+       {0xAB09, 0xAB0E, WBP_ALetter},
+       {0xAB11, 0xAB16, WBP_ALetter},
+       {0xAB20, 0xAB26, WBP_ALetter},
+       {0xAB28, 0xAB2E, WBP_ALetter},
+       {0xABC0, 0xABE2, WBP_ALetter},
+       {0xABE3, 0xABE4, WBP_Extend},
+       {0xABE5, 0xABE5, WBP_Extend},
+       {0xABE6, 0xABE7, WBP_Extend},
+       {0xABE8, 0xABE8, WBP_Extend},
+       {0xABE9, 0xABEA, WBP_Extend},
+       {0xABEC, 0xABEC, WBP_Extend},
+       {0xABED, 0xABED, WBP_Extend},
+       {0xABF0, 0xABF9, WBP_Numeric},
+       {0xAC00, 0xD7A3, WBP_ALetter},
+       {0xD7B0, 0xD7C6, WBP_ALetter},
+       {0xD7CB, 0xD7FB, WBP_ALetter},
+       {0xFB00, 0xFB06, WBP_ALetter},
+       {0xFB13, 0xFB17, WBP_ALetter},
+       {0xFB1D, 0xFB1D, WBP_ALetter},
+       {0xFB1E, 0xFB1E, WBP_Extend},
+       {0xFB1F, 0xFB28, WBP_ALetter},
+       {0xFB2A, 0xFB36, WBP_ALetter},
+       {0xFB38, 0xFB3C, WBP_ALetter},
+       {0xFB3E, 0xFB3E, WBP_ALetter},
+       {0xFB40, 0xFB41, WBP_ALetter},
+       {0xFB43, 0xFB44, WBP_ALetter},
+       {0xFB46, 0xFBB1, WBP_ALetter},
+       {0xFBD3, 0xFD3D, WBP_ALetter},
+       {0xFD50, 0xFD8F, WBP_ALetter},
+       {0xFD92, 0xFDC7, WBP_ALetter},
+       {0xFDF0, 0xFDFB, WBP_ALetter},
+       {0xFE00, 0xFE0F, WBP_Extend},
+       {0xFE10, 0xFE10, WBP_MidNum},
+       {0xFE13, 0xFE13, WBP_MidLetter},
+       {0xFE14, 0xFE14, WBP_MidNum},
+       {0xFE20, 0xFE26, WBP_Extend},
+       {0xFE33, 0xFE34, WBP_ExtendNumLet},
+       {0xFE4D, 0xFE4F, WBP_ExtendNumLet},
+       {0xFE50, 0xFE50, WBP_MidNum},
+       {0xFE52, 0xFE52, WBP_MidNumLet},
+       {0xFE54, 0xFE54, WBP_MidNum},
+       {0xFE55, 0xFE55, WBP_MidLetter},
+       {0xFE70, 0xFE74, WBP_ALetter},
+       {0xFE76, 0xFEFC, WBP_ALetter},
+       {0xFEFF, 0xFEFF, WBP_Format},
+       {0xFF07, 0xFF07, WBP_MidNumLet},
+       {0xFF0C, 0xFF0C, WBP_MidNum},
+       {0xFF0E, 0xFF0E, WBP_MidNumLet},
+       {0xFF1A, 0xFF1A, WBP_MidLetter},
+       {0xFF1B, 0xFF1B, WBP_MidNum},
+       {0xFF21, 0xFF3A, WBP_ALetter},
+       {0xFF3F, 0xFF3F, WBP_ExtendNumLet},
+       {0xFF41, 0xFF5A, WBP_ALetter},
+       {0xFF66, 0xFF6F, WBP_Katakana},
+       {0xFF70, 0xFF70, WBP_Katakana},
+       {0xFF71, 0xFF9D, WBP_Katakana},
+       {0xFF9E, 0xFF9F, WBP_Extend},
+       {0xFFA0, 0xFFBE, WBP_ALetter},
+       {0xFFC2, 0xFFC7, WBP_ALetter},
+       {0xFFCA, 0xFFCF, WBP_ALetter},
+       {0xFFD2, 0xFFD7, WBP_ALetter},
+       {0xFFDA, 0xFFDC, WBP_ALetter},
+       {0xFFF9, 0xFFFB, WBP_Format},
+       {0x10000, 0x1000B, WBP_ALetter},
+       {0x1000D, 0x10026, WBP_ALetter},
+       {0x10028, 0x1003A, WBP_ALetter},
+       {0x1003C, 0x1003D, WBP_ALetter},
+       {0x1003F, 0x1004D, WBP_ALetter},
+       {0x10050, 0x1005D, WBP_ALetter},
+       {0x10080, 0x100FA, WBP_ALetter},
+       {0x10140, 0x10174, WBP_ALetter},
+       {0x101FD, 0x101FD, WBP_Extend},
+       {0x10280, 0x1029C, WBP_ALetter},
+       {0x102A0, 0x102D0, WBP_ALetter},
+       {0x10300, 0x1031E, WBP_ALetter},
+       {0x10330, 0x10340, WBP_ALetter},
+       {0x10341, 0x10341, WBP_ALetter},
+       {0x10342, 0x10349, WBP_ALetter},
+       {0x1034A, 0x1034A, WBP_ALetter},
+       {0x10380, 0x1039D, WBP_ALetter},
+       {0x103A0, 0x103C3, WBP_ALetter},
+       {0x103C8, 0x103CF, WBP_ALetter},
+       {0x103D1, 0x103D5, WBP_ALetter},
+       {0x10400, 0x1044F, WBP_ALetter},
+       {0x10450, 0x1049D, WBP_ALetter},
+       {0x104A0, 0x104A9, WBP_Numeric},
+       {0x10800, 0x10805, WBP_ALetter},
+       {0x10808, 0x10808, WBP_ALetter},
+       {0x1080A, 0x10835, WBP_ALetter},
+       {0x10837, 0x10838, WBP_ALetter},
+       {0x1083C, 0x1083C, WBP_ALetter},
+       {0x1083F, 0x10855, WBP_ALetter},
+       {0x10900, 0x10915, WBP_ALetter},
+       {0x10920, 0x10939, WBP_ALetter},
+       {0x10980, 0x109B7, WBP_ALetter},
+       {0x109BE, 0x109BF, WBP_ALetter},
+       {0x10A00, 0x10A00, WBP_ALetter},
+       {0x10A01, 0x10A03, WBP_Extend},
+       {0x10A05, 0x10A06, WBP_Extend},
+       {0x10A0C, 0x10A0F, WBP_Extend},
+       {0x10A10, 0x10A13, WBP_ALetter},
+       {0x10A15, 0x10A17, WBP_ALetter},
+       {0x10A19, 0x10A33, WBP_ALetter},
+       {0x10A38, 0x10A3A, WBP_Extend},
+       {0x10A3F, 0x10A3F, WBP_Extend},
+       {0x10A60, 0x10A7C, WBP_ALetter},
+       {0x10B00, 0x10B35, WBP_ALetter},
+       {0x10B40, 0x10B55, WBP_ALetter},
+       {0x10B60, 0x10B72, WBP_ALetter},
+       {0x10C00, 0x10C48, WBP_ALetter},
+       {0x11000, 0x11000, WBP_Extend},
+       {0x11001, 0x11001, WBP_Extend},
+       {0x11002, 0x11002, WBP_Extend},
+       {0x11003, 0x11037, WBP_ALetter},
+       {0x11038, 0x11046, WBP_Extend},
+       {0x11066, 0x1106F, WBP_Numeric},
+       {0x11080, 0x11081, WBP_Extend},
+       {0x11082, 0x11082, WBP_Extend},
+       {0x11083, 0x110AF, WBP_ALetter},
+       {0x110B0, 0x110B2, WBP_Extend},
+       {0x110B3, 0x110B6, WBP_Extend},
+       {0x110B7, 0x110B8, WBP_Extend},
+       {0x110B9, 0x110BA, WBP_Extend},
+       {0x110BD, 0x110BD, WBP_Format},
+       {0x110D0, 0x110E8, WBP_ALetter},
+       {0x110F0, 0x110F9, WBP_Numeric},
+       {0x11100, 0x11102, WBP_Extend},
+       {0x11103, 0x11126, WBP_ALetter},
+       {0x11127, 0x1112B, WBP_Extend},
+       {0x1112C, 0x1112C, WBP_Extend},
+       {0x1112D, 0x11134, WBP_Extend},
+       {0x11136, 0x1113F, WBP_Numeric},
+       {0x11180, 0x11181, WBP_Extend},
+       {0x11182, 0x11182, WBP_Extend},
+       {0x11183, 0x111B2, WBP_ALetter},
+       {0x111B3, 0x111B5, WBP_Extend},
+       {0x111B6, 0x111BE, WBP_Extend},
+       {0x111BF, 0x111C0, WBP_Extend},
+       {0x111C1, 0x111C4, WBP_ALetter},
+       {0x111D0, 0x111D9, WBP_Numeric},
+       {0x11680, 0x116AA, WBP_ALetter},
+       {0x116AB, 0x116AB, WBP_Extend},
+       {0x116AC, 0x116AC, WBP_Extend},
+       {0x116AD, 0x116AD, WBP_Extend},
+       {0x116AE, 0x116AF, WBP_Extend},
+       {0x116B0, 0x116B5, WBP_Extend},
+       {0x116B6, 0x116B6, WBP_Extend},
+       {0x116B7, 0x116B7, WBP_Extend},
+       {0x116C0, 0x116C9, WBP_Numeric},
+       {0x12000, 0x1236E, WBP_ALetter},
+       {0x12400, 0x12462, WBP_ALetter},
+       {0x13000, 0x1342E, WBP_ALetter},
+       {0x16800, 0x16A38, WBP_ALetter},
+       {0x16F00, 0x16F44, WBP_ALetter},
+       {0x16F50, 0x16F50, WBP_ALetter},
+       {0x16F51, 0x16F7E, WBP_Extend},
+       {0x16F8F, 0x16F92, WBP_Extend},
+       {0x16F93, 0x16F9F, WBP_ALetter},
+       {0x1B000, 0x1B000, WBP_Katakana},
+       {0x1D165, 0x1D166, WBP_Extend},
+       {0x1D167, 0x1D169, WBP_Extend},
+       {0x1D16D, 0x1D172, WBP_Extend},
+       {0x1D173, 0x1D17A, WBP_Format},
+       {0x1D17B, 0x1D182, WBP_Extend},
+       {0x1D185, 0x1D18B, WBP_Extend},
+       {0x1D1AA, 0x1D1AD, WBP_Extend},
+       {0x1D242, 0x1D244, WBP_Extend},
+       {0x1D400, 0x1D454, WBP_ALetter},
+       {0x1D456, 0x1D49C, WBP_ALetter},
+       {0x1D49E, 0x1D49F, WBP_ALetter},
+       {0x1D4A2, 0x1D4A2, WBP_ALetter},
+       {0x1D4A5, 0x1D4A6, WBP_ALetter},
+       {0x1D4A9, 0x1D4AC, WBP_ALetter},
+       {0x1D4AE, 0x1D4B9, WBP_ALetter},
+       {0x1D4BB, 0x1D4BB, WBP_ALetter},
+       {0x1D4BD, 0x1D4C3, WBP_ALetter},
+       {0x1D4C5, 0x1D505, WBP_ALetter},
+       {0x1D507, 0x1D50A, WBP_ALetter},
+       {0x1D50D, 0x1D514, WBP_ALetter},
+       {0x1D516, 0x1D51C, WBP_ALetter},
+       {0x1D51E, 0x1D539, WBP_ALetter},
+       {0x1D53B, 0x1D53E, WBP_ALetter},
+       {0x1D540, 0x1D544, WBP_ALetter},
+       {0x1D546, 0x1D546, WBP_ALetter},
+       {0x1D54A, 0x1D550, WBP_ALetter},
+       {0x1D552, 0x1D6A5, WBP_ALetter},
+       {0x1D6A8, 0x1D6C0, WBP_ALetter},
+       {0x1D6C2, 0x1D6DA, WBP_ALetter},
+       {0x1D6DC, 0x1D6FA, WBP_ALetter},
+       {0x1D6FC, 0x1D714, WBP_ALetter},
+       {0x1D716, 0x1D734, WBP_ALetter},
+       {0x1D736, 0x1D74E, WBP_ALetter},
+       {0x1D750, 0x1D76E, WBP_ALetter},
+       {0x1D770, 0x1D788, WBP_ALetter},
+       {0x1D78A, 0x1D7A8, WBP_ALetter},
+       {0x1D7AA, 0x1D7C2, WBP_ALetter},
+       {0x1D7C4, 0x1D7CB, WBP_ALetter},
+       {0x1D7CE, 0x1D7FF, WBP_Numeric},
+       {0x1EE00, 0x1EE03, WBP_ALetter},
+       {0x1EE05, 0x1EE1F, WBP_ALetter},
+       {0x1EE21, 0x1EE22, WBP_ALetter},
+       {0x1EE24, 0x1EE24, WBP_ALetter},
+       {0x1EE27, 0x1EE27, WBP_ALetter},
+       {0x1EE29, 0x1EE32, WBP_ALetter},
+       {0x1EE34, 0x1EE37, WBP_ALetter},
+       {0x1EE39, 0x1EE39, WBP_ALetter},
+       {0x1EE3B, 0x1EE3B, WBP_ALetter},
+       {0x1EE42, 0x1EE42, WBP_ALetter},
+       {0x1EE47, 0x1EE47, WBP_ALetter},
+       {0x1EE49, 0x1EE49, WBP_ALetter},
+       {0x1EE4B, 0x1EE4B, WBP_ALetter},
+       {0x1EE4D, 0x1EE4F, WBP_ALetter},
+       {0x1EE51, 0x1EE52, WBP_ALetter},
+       {0x1EE54, 0x1EE54, WBP_ALetter},
+       {0x1EE57, 0x1EE57, WBP_ALetter},
+       {0x1EE59, 0x1EE59, WBP_ALetter},
+       {0x1EE5B, 0x1EE5B, WBP_ALetter},
+       {0x1EE5D, 0x1EE5D, WBP_ALetter},
+       {0x1EE5F, 0x1EE5F, WBP_ALetter},
+       {0x1EE61, 0x1EE62, WBP_ALetter},
+       {0x1EE64, 0x1EE64, WBP_ALetter},
+       {0x1EE67, 0x1EE6A, WBP_ALetter},
+       {0x1EE6C, 0x1EE72, WBP_ALetter},
+       {0x1EE74, 0x1EE77, WBP_ALetter},
+       {0x1EE79, 0x1EE7C, WBP_ALetter},
+       {0x1EE7E, 0x1EE7E, WBP_ALetter},
+       {0x1EE80, 0x1EE89, WBP_ALetter},
+       {0x1EE8B, 0x1EE9B, WBP_ALetter},
+       {0x1EEA1, 0x1EEA3, WBP_ALetter},
+       {0x1EEA5, 0x1EEA9, WBP_ALetter},
+       {0x1EEAB, 0x1EEBB, WBP_ALetter},
+       {0x1F1E6, 0x1F1FF, WBP_Regional},
+       {0xE0001, 0xE0001, WBP_Format},
+       {0xE0020, 0xE007F, WBP_Format},
+       {0xE0100, 0xE01EF, WBP_Extend},
+       {0xFFFFFFFF, 0xFFFFFFFF, WBP_Undefined}
+};
diff --git a/text/dali/internal/libunibreak/wordbreakdef.h b/text/dali/internal/libunibreak/wordbreakdef.h
new file mode 100644 (file)
index 0000000..72816f9
--- /dev/null
@@ -0,0 +1,88 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013 Tom Hacohen <tom at stosb dot com>
+ * Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 21, for
+ * Unicode 6.2.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-21.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreakdef.h
+ *
+ * Definitions of internal data structures, declarations of global
+ * variables, and function prototypes for the word breaking algorithm.
+ *
+ * @version 2.4, 2013/11/10
+ * @author  Tom Hacohen
+ * @author  Petr Filipsky
+ */
+
+/**
+ * Word break classes.  This is a direct mapping of Table 3 of Unicode
+ * Standard Annex 29, Revision 23.
+ */
+enum WordBreakClass
+{
+    WBP_Undefined,
+    WBP_CR,
+    WBP_LF,
+    WBP_Newline,
+    WBP_Extend,
+    WBP_Format,
+    WBP_Katakana,
+    WBP_ALetter,
+    WBP_MidNumLet,
+    WBP_MidLetter,
+    WBP_MidNum,
+    WBP_Numeric,
+    WBP_ExtendNumLet,
+    WBP_Regional,
+    WBP_Hebrew,
+    WBP_Single,
+    WBP_Double,
+    WBP_Any
+};
+
+/**
+ * Struct for entries of word break properties.  The array of the
+ * entries \e must be sorted.
+ */
+struct WordBreakProperties
+{
+    utf32_t start;              /**< Starting coding point */
+    utf32_t end;                /**< End coding point */
+    enum WordBreakClass prop;   /**< The word breaking property */
+};
diff --git a/text/dali/internal/text-abstraction/bidirectional-support-impl.cpp b/text/dali/internal/text-abstraction/bidirectional-support-impl.cpp
new file mode 100644 (file)
index 0000000..607a970
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include "bidirectional-support-impl.h"
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <fribidi/fribidi.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+namespace
+{
+  typedef unsigned char BidiDirection;
+
+  // Internal charcter's direction.
+  const BidiDirection LEFT_TO_RIGHT = 0u;
+  const BidiDirection NEUTRAL = 1u;
+  const BidiDirection RIGHT_TO_LEFT = 2u;
+
+  /**
+   * @param[in] paragraphDirection The FriBiDi paragraph's direction.
+   *
+   * @return Whether the paragraph is right to left.
+   */
+  bool GetBidiParagraphDirection( FriBidiParType paragraphDirection )
+  {
+    switch( paragraphDirection )
+    {
+      case FRIBIDI_PAR_RTL:  // Right-To-Left paragraph.
+      case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
+      {
+        return true;
+      }
+      case FRIBIDI_PAR_LTR:  // Left-To-Right paragraph.
+      case FRIBIDI_PAR_ON:   // DirectiOn-Neutral paragraph.
+      case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
+      {
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  BidiDirection GetBidiCharacterDirection( FriBidiCharType characterDirection )
+  {
+    switch( characterDirection )
+    {
+      case FRIBIDI_TYPE_LTR: // Left-To-Right letter.
+      case FRIBIDI_TYPE_EN:  // European Numeral.
+      case FRIBIDI_TYPE_AN:  // Arabic Numeral.
+      case FRIBIDI_TYPE_ES:  // European number Separator.
+      case FRIBIDI_TYPE_ET:  // European number Terminator.
+      {
+        return LEFT_TO_RIGHT;
+      }
+      case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
+      case FRIBIDI_TYPE_AL:  // Arabic Letter.
+      {
+        return RIGHT_TO_LEFT;
+      }
+    }
+
+    return NEUTRAL;
+  }
+}
+
+struct BidirectionalSupport::Plugin
+{
+  /**
+   * Stores bidirectional info per paragraph.
+   */
+  struct BidirectionalInfo
+  {
+    FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
+    FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
+    FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
+  };
+
+  Plugin()
+  : mParagraphBidirectionalInfo(),
+    mFreeIndices()
+  {}
+
+  ~Plugin()
+  {
+    // free all resources.
+    for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
+           endIt = mParagraphBidirectionalInfo.End();
+         it != endIt;
+         ++it )
+    {
+      BidirectionalInfo* info = *it;
+
+      free( info->embeddedLevels );
+      free( info->characterTypes );
+      delete info;
+    }
+  }
+
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters )
+  {
+    // Reserve memory for the paragraph's bidirectional info.
+    BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
+
+    bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
+    if( !bidirectionalInfo->characterTypes )
+    {
+      delete bidirectionalInfo;
+      return 0;
+    }
+
+    bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
+    if( !bidirectionalInfo->embeddedLevels )
+    {
+      free( bidirectionalInfo->characterTypes );
+      delete bidirectionalInfo;
+      return 0;
+    }
+
+    // Retrieve the type of each character..
+    fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
+
+    // Retrieve the paragraph's direction.
+    bidirectionalInfo->paragraphDirection = fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters );
+
+    // Retrieve the embedding levels.
+    fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels );
+
+    // Store the bidirectional info and return the index.
+    BidiInfoIndex index = 0u;
+    if( 0u != mFreeIndices.Count() )
+    {
+      Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
+
+      index = *it;
+
+      mFreeIndices.Remove( it );
+
+      *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
+    }
+    else
+    {
+      index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );
+
+      mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
+    }
+
+    return index;
+  }
+
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex )
+  {
+    if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
+    {
+      return;
+    }
+
+    // Retrieve the paragraph's bidirectional info.
+    Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
+    BidirectionalInfo* bidirectionalInfo = *it;
+
+    if( NULL != bidirectionalInfo )
+    {
+      // Free resources and destroy the container.
+      free( bidirectionalInfo->embeddedLevels );
+      free( bidirectionalInfo->characterTypes );
+      delete bidirectionalInfo;
+
+      *it = NULL;
+    }
+
+    // Add the index to the free indices vector.
+    mFreeIndices.PushBack( bidiInfoIndex );
+  }
+
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap )
+  {
+    const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
+
+    // Retrieve the paragraph's bidirectional info.
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      visualToLogicalMap[ index ] = index;
+    }
+
+    // Copy embedded levels as fribidi_reorder_line() may change them.
+    const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
+    FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
+    if( embeddedLevels )
+    {
+      memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );
+
+      // Reorder the line.
+      fribidi_reorder_line( flags,
+                            bidirectionalInfo->characterTypes + firstCharacterIndex,
+                            numberOfCharacters,
+                            0u,
+                            bidirectionalInfo->paragraphDirection,
+                            embeddedLevels,
+                            NULL,
+                            reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) );
+
+      // Free resources.
+      free( embeddedLevels );
+    }
+  }
+
+  bool GetMirroredText( Character* text,
+                        Length numberOfCharacters ) const
+  {
+    bool updated = false;
+
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      // Get a reference to the character inside the text.
+      Character& character = *( text + index );
+
+      // Retrieve the mirrored character.
+      FriBidiChar mirroredCharacter = character;
+      const bool mirrored = fribidi_get_mirror_char( character, &mirroredCharacter );
+      updated = updated || mirrored;
+
+      // Update the character inside the text.
+      character = mirroredCharacter;
+    }
+
+    return updated;
+  }
+
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+  {
+    // Retrieve the paragraph's bidirectional info.
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    return GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
+  }
+
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters )
+  {
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    const CharacterDirection paragraphDirection = GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
+    CharacterDirection previousDirection = paragraphDirection;
+
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      CharacterDirection& characterDirection = *( directions + index );
+      characterDirection = false;
+
+      // Get the bidi direction.
+      const BidiDirection bidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + index ) );
+
+      if( RIGHT_TO_LEFT == bidiDirection )
+      {
+        characterDirection = true;
+      }
+      else if( NEUTRAL == bidiDirection )
+      {
+        // For neutral characters it check's the next and previous directions.
+        // If they are equals set that direction. If they are not, sets the paragraph's direction.
+        // If there is no next, sets the paragraph's direction.
+
+        CharacterDirection nextDirection = paragraphDirection;
+
+        // Look for the next non-neutral character.
+        Length nextIndex = index + 1u;
+        for( ; nextIndex < numberOfCharacters; ++nextIndex )
+        {
+          BidiDirection nextBidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + nextIndex ) );
+          if( nextBidiDirection != NEUTRAL )
+          {
+            nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
+            break;
+          }
+        }
+
+        // Calculate the direction for all the neutral characters.
+        characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
+
+        // Set the direction to all the neutral characters.
+        ++index;
+        for( ; index < nextIndex; ++index )
+        {
+          CharacterDirection& nextCharacterDirection = *( directions + index );
+          nextCharacterDirection = characterDirection;
+        }
+
+        // Set the direction of the next non-neutral character.
+        if( nextIndex < numberOfCharacters )
+        {
+          *( directions + nextIndex ) = nextDirection;
+        }
+      }
+
+      previousDirection = characterDirection;
+    }
+  }
+
+  Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
+  Vector<BidiInfoIndex>      mFreeIndices;                ///< Stores indices of free positions in the bidirectional info vector.
+};
+
+BidirectionalSupport::BidirectionalSupport()
+: mPlugin( NULL )
+{
+}
+
+BidirectionalSupport::~BidirectionalSupport()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
+{
+  TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
+      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
+    }
+    else // create and register the object
+    {
+      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
+      service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
+    }
+  }
+
+  return bidirectionalSupportHandle;
+}
+
+BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
+                                                Length numberOfCharacters )
+{
+  CreatePlugin();
+
+  return mPlugin->CreateInfo( paragraph,
+                              numberOfCharacters );
+}
+
+void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
+{
+  CreatePlugin();
+
+  mPlugin->DestroyInfo( bidiInfoIndex );
+}
+
+void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
+                                    CharacterIndex firstCharacterIndex,
+                                    Length numberOfCharacters,
+                                    CharacterIndex* visualToLogicalMap )
+{
+  CreatePlugin();
+
+  mPlugin->Reorder( bidiInfoIndex,
+                    firstCharacterIndex,
+                    numberOfCharacters,
+                    visualToLogicalMap );
+}
+
+bool BidirectionalSupport::GetMirroredText( Character* text,
+                                            Length numberOfCharacters )
+{
+  CreatePlugin();
+
+  return mPlugin->GetMirroredText( text, numberOfCharacters );
+}
+
+bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+{
+  if( !mPlugin )
+  {
+    return false;
+  }
+
+  return mPlugin->GetParagraphDirection( bidiInfoIndex );
+}
+
+void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                                                   CharacterDirection* directions,
+                                                   Length numberOfCharacters )
+{
+  CreatePlugin();
+
+  mPlugin->GetCharactersDirection( bidiInfoIndex,
+                                   directions,
+                                   numberOfCharacters );
+}
+
+void BidirectionalSupport::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/bidirectional-support-impl.h b/text/dali/internal/text-abstraction/bidirectional-support-impl.h
new file mode 100644 (file)
index 0000000..cbbb05f
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the BidirectionalSupport
+ */
+class BidirectionalSupport : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  BidirectionalSupport();
+
+  /**
+   * Destructor
+   */
+  ~BidirectionalSupport();
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::Get()
+   */
+  static TextAbstraction::BidirectionalSupport Get();
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::CreateInfo()
+   */
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::DestroyInfo()
+   */
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::Reorder()
+   */
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetMirroredText()
+   */
+  bool GetMirroredText( Character* text,
+                        Length numberOfCharacters );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetParagraphDirection()
+   */
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const;
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetCharactersDirection()
+   */
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  BidirectionalSupport( const BidirectionalSupport& );
+
+  // Undefined assignment constructor.
+  BidirectionalSupport& operator=( BidirectionalSupport& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class BidirectionalSupport
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::BidirectionalSupport& GetImplementation( TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  BaseObject& handle = bidirectionalSupport.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::BidirectionalSupport&>(handle);
+}
+
+inline static const TextAbstraction::Internal::BidirectionalSupport& GetImplementation( const TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  const BaseObject& handle = bidirectionalSupport.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::BidirectionalSupport&>(handle);
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H__
diff --git a/text/dali/internal/text-abstraction/font-client-helper.cpp b/text/dali/internal/text-abstraction/font-client-helper.cpp
new file mode 100644 (file)
index 0000000..d7e3e16
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include "font-client-helper.h"
+
+// INTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+}
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+int ValueToIndex( int value, const int* const table, unsigned int maxIndex )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->FontClient::Plugin::ValueToIndex value(%d)\n", value);
+
+  if( ( NULL == table ) ||
+      ( value <= table[0] ) )
+  {
+    return 0;
+  }
+
+  if( value >= table[maxIndex] )
+  {
+    return maxIndex;
+  }
+
+  for( unsigned int index = 0u; index < maxIndex; )
+  {
+    const int v1 = table[index];
+    const unsigned int indexPlus = ++index;
+    const int v2 = table[indexPlus];
+    if( ( v1 < value ) && ( value <= v2 ) )
+    {
+      const int result = ( ( value - v1 ) < ( v2 - value ) ) ? index : indexPlus;
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex result(%d)\n",  result );
+      return result;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex exit 0 <-- \n");
+
+  return 0;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/font-client-helper.h b/text/dali/internal/text-abstraction/font-client-helper.h
new file mode 100644 (file)
index 0000000..52d7898
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H__
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Retrieves a table index for a given value.
+ *
+ * @param[in] value The value.
+ * @param[in] table The table.
+ * @param[in] maxIndex The maximum valid index of the table.
+ *
+ * @return The index to the closest available value
+ */
+int ValueToIndex( int value, const int* const table, unsigned int maxIndex );
+
+} // Internal
+
+} // TextAbstraction
+
+} // Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H__
diff --git a/text/dali/internal/text-abstraction/font-client-impl.cpp b/text/dali/internal/text-abstraction/font-client-impl.cpp
new file mode 100644 (file)
index 0000000..b77d3bf
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service.h>
+#include <dali/internal/text-abstraction/font-client-plugin-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+FontClient::FontClient()
+: mPlugin( NULL ),
+  mDpiHorizontal( 0 ),
+  mDpiVertical( 0 )
+{
+}
+
+FontClient::~FontClient()
+{
+  delete mPlugin;
+}
+
+Dali::TextAbstraction::FontClient FontClient::Get()
+{
+  Dali::TextAbstraction::FontClient fontClientHandle;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
+      fontClientHandle = Dali::TextAbstraction::FontClient( impl );
+    }
+    else // create and register the object
+    {
+      fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
+      service.Register( typeid( fontClientHandle ), fontClientHandle );
+    }
+  }
+
+  return fontClientHandle;
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
+{
+  mDpiHorizontal = horizontalDpi;
+  mDpiVertical = verticalDpi;
+
+  // Allow DPI to be set without loading plugin
+  if( mPlugin )
+  {
+    mPlugin->SetDpi( horizontalDpi, verticalDpi  );
+  }
+}
+
+void FontClient::GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi )
+{
+  horizontalDpi = mDpiHorizontal;
+  verticalDpi = mDpiVertical;
+}
+
+void FontClient::SetDefaultFont( const FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  mPlugin->SetDefaultFont( fontDescription );
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+  CreatePlugin();
+
+  mPlugin->GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  mPlugin->GetDefaultPlatformFontDescription( fontDescription );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  mPlugin->GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+  CreatePlugin();
+
+  return mPlugin->GetPointSize( id );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+  CreatePlugin();
+
+  mPlugin->GetSystemFonts( systemFonts );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  CreatePlugin();
+
+  return mPlugin->FindDefaultFont( charcode, pointSize, preferColor );
+}
+
+FontId FontClient::FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  CreatePlugin();
+
+  return mPlugin->FindFallbackFont( preferredFont, charcode, pointSize, preferColor );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+  CreatePlugin();
+
+  return mPlugin->IsScalable( path );
+}
+
+bool FontClient::IsScalable( const FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  return mPlugin->IsScalable( fontDescription );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+  CreatePlugin();
+
+  mPlugin->GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontDescription& fontDescription,
+                                Dali::Vector< PointSize26Dot6 >& sizes )
+{
+  CreatePlugin();
+
+  mPlugin->GetFixedSizes( fontDescription, sizes );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( path, pointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontDescription& fontDescription,
+                              PointSize26Dot6 pointSize,
+                              FaceIndex faceIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( fontDescription,
+                             pointSize,
+                             faceIndex );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics, int maxFixedSize )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontMetrics( fontId, metrics, maxFixedSize );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+  CreatePlugin();
+
+  return mPlugin->GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int maxFixedSize )
+{
+  CreatePlugin();
+
+  return mPlugin->GetGlyphMetrics( array, size, horizontal, maxFixedSize );
+}
+
+BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->CreateBitmap( fontId, glyphIndex );
+}
+
+const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 pointSize )
+{
+  CreatePlugin();
+
+  return mPlugin->GetEllipsisGlyph( pointSize );
+}
+
+void FontClient::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/font-client-impl.h b/text/dali/internal/text-abstraction/font-client-impl.h
new file mode 100644 (file)
index 0000000..2d5596d
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the FontClient
+ */
+class FontClient : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  FontClient();
+
+  /**
+   * Destructor
+   */
+  ~FontClient();
+
+  /**
+   * @copydoc Dali::FontClient::Get()
+   */
+  static Dali::TextAbstraction::FontClient Get();
+
+  /**
+   * @copydoc Dali::FontClient::SetDpi()
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @copydoc Dali::FontClient::GetDpi()
+   */
+  void GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi );
+
+  /**
+   * @copydoc Dali::FontClient::SetDefaultFont()
+   */
+  void SetDefaultFont( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetDefaultFonts()
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @copydoc Dali::FontClient::GetDefaultPlatformFontDescription()
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetSystemFonts()
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @copydoc Dali::FontClient::GetDescription()
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetPointSize()
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @copydoc Dali::FontClient::FindDefaultFont()
+   */
+  FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor );
+
+  /**
+   * @copydoc Dali::FontClient::FindFallbackFont()
+   */
+  FontId FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 pointSize, bool preferColor );
+
+  /**
+   * @copydoc Dali::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::FontClient::GetFontId( const FontDescription& fontDescription, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontDescription& fontDescription,
+                    PointSize26Dot6 pointSize,
+                    FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::FontClient::IsScalable( const FontPath& path )
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @copydoc Dali::FontClient::IsScalable( const FontDescription& fontDescription )
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @copydoc Dali::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  /**
+   * @copydoc Dali::FontClient::GetFontMetrics()
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics, int maxFixedSize );
+
+  /**
+   * @copydoc Dali::FontClient::GetGlyphIndex()
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @copydoc Dali::FontClient::GetGlyphMetrics()
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int maxFixedSize );
+
+  /**
+   * @copydoc Dali::FontClient::CreateBitmap()
+   */
+  BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @copydoc Dali::FontClient::GetEllipsisGlyph()
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+  // Undefined copy constructor.
+  FontClient( const FontClient& );
+
+  // Undefined assignment constructor.
+  FontClient& operator=( FontClient& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+  // Allows DPI to be set without loading plugin
+  unsigned int mDpiHorizontal;
+  unsigned int mDpiVertical;
+
+}; // class FontClient
+
+} // namespace Internal
+
+inline static Internal::FontClient& GetImplementation(FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<Internal::FontClient&>(handle);
+}
+
+inline static const Internal::FontClient& GetImplementation(const FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  const BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<const Internal::FontClient&>(handle);
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
diff --git a/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp b/text/dali/internal/text-abstraction/font-client-plugin-impl.cpp
new file mode 100644 (file)
index 0000000..078cf8e
--- /dev/null
@@ -0,0 +1,1442 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text-abstraction/font-client-plugin-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-list.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/text-abstraction/font-client-helper.h>
+#include <adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+
+/**
+ * Conversion from Fractional26.6 to float
+ */
+const float FROM_266 = 1.0f / 64.0f;
+
+const std::string FONT_FORMAT( "TrueType" );
+const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
+const int DEFAULT_FONT_WIDTH  = 100; // normal
+const int DEFAULT_FONT_WEIGHT =  80; // normal
+const int DEFAULT_FONT_SLANT  =   0; // normal
+
+const uint32_t ELLIPSIS_CHARACTER = 0x2026;
+
+const bool FONT_FIXED_SIZE_BITMAP( true );
+
+// http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+// ULTRA_CONDENSED 50
+// EXTRA_CONDENSED 63
+// CONDENSED       75
+// SEMI_CONDENSED  87
+// NORMAL         100
+// SEMI_EXPANDED  113
+// EXPANDED       125
+// EXTRA_EXPANDED 150
+// ULTRA_EXPANDED 200
+const int FONT_WIDTH_TYPE_TO_INT[] = { 50, 63, 75, 87, 100, 113, 125, 150, 200 };
+const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
+
+// THIN                        0
+// ULTRA_LIGHT, EXTRA_LIGHT   40
+// LIGHT                      50
+// DEMI_LIGHT, SEMI_LIGHT     55
+// BOOK                       75
+// NORMAL, REGULAR            80
+// MEDIUM                    100
+// DEMI_BOLD, SEMI_BOLD      180
+// BOLD                      200
+// ULTRA_BOLD, EXTRA_BOLD    205
+// BLACK, HEAVY, EXTRA_BLACK 210
+const int FONT_WEIGHT_TYPE_TO_INT[] = { 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
+const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
+
+// NORMAL, ROMAN   0
+// ITALIC        100
+// OBLIQUE       110
+const int FONT_SLANT_TYPE_TO_INT[] = { 0, 100, 110 };
+const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
+
+} // namespace
+
+using Dali::Vector;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Returns the FontWidth's enum index for the given width value.
+ *
+ * @param[in] width The width value.
+ *
+ * @return The FontWidth's enum index.
+ */
+FontWidth::Type IntToWidthType( int width )
+{
+  return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
+}
+
+/**
+ * @brief Returns the FontWeight's enum index for the given weight value.
+ *
+ * @param[in] weight The weight value.
+ *
+ * @return The FontWeight's enum index.
+ */
+FontWeight::Type IntToWeightType( int weight )
+{
+  return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
+}
+
+/**
+ * @brief Returns the FontSlant's enum index for the given slant value.
+ *
+ * @param[in] slant The slant value.
+ *
+ * @return The FontSlant's enum index.
+ */
+FontSlant::Type IntToSlantType( int slant )
+{
+  return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
+}
+
+FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( const FontDescription& font, FontList* list )
+: fontDescription( font ),
+  fallbackFonts( list )
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
+                                                                        FontDescriptionId index )
+: fontDescription( fontDescription ),
+  index( index )
+{
+}
+
+FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
+                                                      PointSize26Dot6 pointSize,
+                                                      FontId fontId )
+: validatedFontId( validatedFontId ),
+  pointSize( pointSize ),
+  fontId( fontId )
+{
+}
+
+FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
+                                          const FontPath& path,
+                                          PointSize26Dot6 pointSize,
+                                          FaceIndex face,
+                                          const FontMetrics& metrics )
+: mFreeTypeFace( ftFace ),
+  mPath( path ),
+  mPointSize( pointSize ),
+  mFaceIndex( face ),
+  mMetrics( metrics ),
+  mFixedWidthPixels( 0.0f ),
+  mFixedHeightPixels( 0.0f ),
+  mIsFixedSizeBitmap( false )
+{
+}
+
+FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
+                                          const FontPath& path,
+                                          PointSize26Dot6 pointSize,
+                                          FaceIndex face,
+                                          const FontMetrics& metrics,
+                                          float fixedWidth,
+                                          float fixedHeight )
+: mFreeTypeFace( ftFace ),
+  mPath( path ),
+  mPointSize( pointSize ),
+  mFaceIndex( face ),
+  mMetrics( metrics ),
+  mFixedWidthPixels( fixedWidth ),
+  mFixedHeightPixels( fixedHeight ),
+  mIsFixedSizeBitmap( true )
+{
+}
+
+FontClient::Plugin::Plugin( unsigned int horizontalDpi,
+                            unsigned int verticalDpi )
+: mFreeTypeLibrary( NULL ),
+  mDpiHorizontal( horizontalDpi ),
+  mDpiVertical( verticalDpi ),
+  mSystemFonts(),
+  mDefaultFonts(),
+  mFontCache(),
+  mValidatedFontCache(),
+  mFontDescriptionCache( 1u ),
+  mFontIdCache(),
+  mEllipsisCache()
+{
+  int error = FT_Init_FreeType( &mFreeTypeLibrary );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
+  }
+}
+
+FontClient::Plugin::~Plugin()
+{
+  for( std::vector<FallbackCacheItem>::iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
+       it != endIt;
+       ++it )
+  {
+    FallbackCacheItem& item = *it;
+
+    if( item.fallbackFonts )
+    {
+      delete item.fallbackFonts;
+      item.fallbackFonts = NULL;
+    }
+  }
+
+  FT_Done_FreeType( mFreeTypeLibrary );
+}
+
+void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
+                                 unsigned int verticalDpi )
+{
+  mDpiHorizontal = horizontalDpi;
+  mDpiVertical = verticalDpi;
+}
+
+void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::SetFontList family(%s)\n", fontDescription.family.c_str() );
+
+  fontList.clear();
+
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
+
+  FcResult result = FcResultMatch;
+
+  // Match the pattern.
+  FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
+                                   fontFamilyPattern,
+                                   false /* don't trim */,
+                                   NULL,
+                                   &result );
+
+  if( NULL != fontSet )
+  {
+    // Reserve some space to avoid reallocations.
+    fontList.reserve( fontSet->nfont );
+
+    for( int i = 0u; i < fontSet->nfont; ++i )
+    {
+      FcPattern* fontPattern = fontSet->fonts[i];
+
+      FontPath path;
+
+      // Skip fonts with no path
+      if( GetFcString( fontPattern, FC_FILE, path ) )
+      {
+        fontList.push_back( FontDescription() );
+        FontDescription& newFontDescription = fontList.back();
+
+        newFontDescription.path = path;
+
+        int width = 0;
+        int weight = 0;
+        int slant = 0;
+        GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
+        GetFcInt( fontPattern, FC_WIDTH, width );
+        GetFcInt( fontPattern, FC_WEIGHT, weight );
+        GetFcInt( fontPattern, FC_SLANT, slant );
+        newFontDescription.width = IntToWidthType( width );
+        newFontDescription.weight = IntToWeightType( weight );
+        newFontDescription.slant = IntToSlantType( slant );
+      }
+    }
+
+    FcFontSetDestroy( fontSet );
+  }
+
+  FcPatternDestroy( fontFamilyPattern );
+}
+
+void FontClient::Plugin::SetDefaultFont( const FontDescription& fontDescription )
+{
+  SetFontList( fontDescription, mDefaultFonts );
+}
+
+void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultFonts mDefaultFonts(%s)\n", ( mDefaultFonts.empty()?"empty":"valid" ) );
+
+  if( mDefaultFonts.empty() )
+  {
+    FontDescription fontDescription;
+    fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
+    fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+    fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+    fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+    SetFontList( fontDescription, mDefaultFonts );
+  }
+
+  defaultFonts = mDefaultFonts;
+}
+
+void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetDefaultPlatformFontDescription\n");
+
+  FcInitReinitialize(); // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
+
+  FcPattern* matchPattern = FcPatternCreate();
+  FcConfigSubstitute(NULL, matchPattern, FcMatchPattern);
+  FcDefaultSubstitute( matchPattern );
+
+  MatchFontDescriptionToPattern( matchPattern, fontDescription );
+  FcPatternDestroy( matchPattern );
+}
+
+void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetSystemFonts\n");
+
+  if( mSystemFonts.empty() )
+  {
+    InitSystemFonts();
+  }
+
+  systemFonts = mSystemFonts;
+}
+
+void FontClient::Plugin::GetDescription( FontId id,
+                                         FontDescription& fontDescription ) const
+{
+  for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
+         endIt = mFontIdCache.end();
+       it != endIt;
+       ++it )
+  {
+    const FontIdCacheItem& item = *it;
+
+    if( item.fontId == id )
+    {
+      fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
+      return;
+    }
+  }
+
+  DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
+}
+
+PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
+{
+  const FontId index = id - 1u;
+
+  if( id > 0u &&
+      index < mFontCache.size() )
+  {
+    return ( *( mFontCache.begin() + index ) ).mPointSize;
+  }
+  else
+  {
+    DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
+  }
+
+  return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+}
+
+FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
+                                                 Character charcode,
+                                                 PointSize26Dot6 requestedSize,
+                                                 bool preferColor )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFontForCharacter\n");
+
+  FontId fontId(0);
+  bool foundColor(false);
+
+  // Traverse the list of fonts.
+  // Check for each default font if supports the character.
+
+  for( FontList::const_iterator it = fontList.begin(), endIt = fontList.end();
+       it != endIt;
+       ++it )
+  {
+    const FontDescription& description = *it;
+
+    FcPattern* pattern = CreateFontFamilyPattern( description );
+
+    FcResult result = FcResultMatch;
+    FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
+
+    FcCharSet* charSet = NULL;
+    FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
+
+    if( FcCharSetHasChar( charSet, charcode ) )
+    {
+      Vector< PointSize26Dot6 > fixedSizes;
+      GetFixedSizes( description,
+                     fixedSizes );
+
+      const Vector< PointSize26Dot6 >::SizeType count = fixedSizes.Count();
+      if( 0 != count )
+      {
+        // If the font is not scalable, pick the largest size <= requestedSize
+        PointSize26Dot6 size = fixedSizes[0];
+        for( unsigned int i=1; i<count; ++i )
+        {
+          if( fixedSizes[i] <= requestedSize &&
+              fixedSizes[i] > size )
+          {
+            size = fixedSizes[i];
+          }
+        }
+        requestedSize = size;
+      }
+
+      fontId = GetFontId( description,
+                          requestedSize,
+                          0u );
+
+      if( preferColor )
+      {
+        BufferImage bitmap = CreateBitmap( fontId, GetGlyphIndex(fontId,charcode) );
+        if( bitmap &&
+            Pixel::BGRA8888 == bitmap.GetPixelFormat() )
+        {
+          foundColor = true;
+        }
+      }
+
+      // Keep going unless we prefer a different (color) font
+      if( !preferColor || foundColor )
+      {
+        FcPatternDestroy( match );
+        FcPatternDestroy( pattern );
+        break;
+      }
+    }
+
+    FcPatternDestroy( match );
+    FcPatternDestroy( pattern );
+  }
+
+  return fontId;
+}
+
+FontId FontClient::Plugin::FindDefaultFont( Character charcode,
+                                            PointSize26Dot6 requestedSize,
+                                            bool preferColor )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindDefaultFont DefaultFontsList(%s)\n", (mDefaultFonts.empty()?"empty":"created") );
+
+  FontId fontId(0);
+
+  // Create the list of default fonts if it has not been created.
+  if( mDefaultFonts.empty() )
+  {
+    FontDescription fontDescription;
+    fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
+    fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+    fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+    fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+    SetFontList( fontDescription, mDefaultFonts );
+  }
+
+  // Traverse the list of default fonts.
+  // Check for each default font if supports the character.
+  fontId = FindFontForCharacter( mDefaultFonts, charcode, requestedSize, preferColor );
+
+  return fontId;
+}
+
+FontId FontClient::Plugin::FindFallbackFont( FontId preferredFont,
+                                             Character charcode,
+                                             PointSize26Dot6 requestedSize,
+                                             bool preferColor )
+{
+  // The font id to be returned.
+  FontId fontId = 0u;
+
+  FontDescription fontDescription;
+  GetDescription( preferredFont, fontDescription );
+
+  // Check first if the font's description has been queried before.
+  FontList* fontList( NULL );
+
+  if( !FindFallbackFontList( fontDescription, fontList ) )
+  {
+    fontList = new FontList;
+    SetFontList( fontDescription, *fontList );
+
+    // Add the font-list to the cache.
+    mFallbackCache.push_back( FallbackCacheItem(fontDescription, fontList) );
+  }
+
+  if( fontList )
+  {
+    fontId = FindFontForCharacter( *fontList, charcode, requestedSize, preferColor );
+  }
+
+  return fontId;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontPath& path,
+                                      PointSize26Dot6 pointSize,
+                                      FaceIndex faceIndex,
+                                      bool cacheDescription )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId fontPatch:%s\n", path.c_str() );
+
+  FontId id( 0 );
+
+  if( NULL != mFreeTypeLibrary )
+  {
+    FontId foundId(0);
+    if( FindFont( path, pointSize, faceIndex, foundId ) )
+    {
+      id = foundId;
+    }
+    else
+    {
+      id = CreateFont( path, pointSize, faceIndex, cacheDescription );
+    }
+  }
+
+  return id;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
+                                      PointSize26Dot6 pointSize,
+                                      FaceIndex faceIndex )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId font family(%s)\n", fontDescription.family.c_str() );
+
+  // This method uses three vectors which caches:
+  // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
+  // * The path to font file names.
+  // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
+
+  // 1) Checks in the cache if the font's description has been validated before.
+  //    If it was it gets an index to the vector with paths to font file names. Otherwise,
+  //    retrieves using font config a path to a font file name which matches with the
+  //    font's description. The path is stored in the cache.
+  //
+  // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
+  //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
+  //    the GetFontId() method with the path to the font file name and the point size to
+  //    get the font id.
+
+  // The font id to be returned.
+  FontId fontId = 0u;
+
+  // Check first if the font's description have been validated before.
+  FontDescriptionId validatedFontId = 0u;
+
+  if( !FindValidatedFont( fontDescription,
+                          validatedFontId ) )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::GetFontId Validating Font\n");
+
+    // Use font config to validate the font's description.
+    ValidateFont( fontDescription,
+                  validatedFontId );
+  }
+
+  // Check if exists a pair 'validatedFontId, pointSize' in the cache.
+  if( !FindFont( validatedFontId, pointSize, fontId ) )
+  {
+    // Retrieve the font file name path.
+    const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
+
+    // Retrieve the font id. Do not cache the description as it has been already cached.
+    fontId = GetFontId( description.path,
+                        pointSize,
+                        faceIndex,
+                        false );
+
+    // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
+    mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
+                                             pointSize,
+                                             fontId ) );
+  }
+
+  return fontId;
+}
+
+void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
+                                       FontDescriptionId& validatedFontId )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont Validating Font family(%s) \n", fontDescription.family.c_str() );
+
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
+
+  FontDescription description;
+
+  bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description );
+  FcPatternDestroy( fontFamilyPattern );
+
+  if( matched )
+  {
+    // Set the index to the vector of paths to font file names.
+    validatedFontId = mFontDescriptionCache.size();
+
+    // Add the path to the cache.
+    mFontDescriptionCache.push_back( description );
+
+    // Cache the index and the font's description.
+    FontDescriptionCacheItem item( description,
+                                   validatedFontId );
+
+    mValidatedFontCache.push_back( item );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %d %d %d\n",
+                    fontDescription.family.c_str(),
+                    fontDescription.width,
+                    fontDescription.weight,
+                    fontDescription.slant );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValidateFont validatedFontId(%u) font family(%s)\n", validatedFontId, fontDescription.family.c_str() );
+}
+
+void FontClient::Plugin::GetFontMetrics( FontId fontId,
+                                         FontMetrics& metrics,
+                                         int maxFixedSize )
+{
+  if( fontId > 0 &&
+      fontId-1 < mFontCache.size() )
+  {
+    const CacheItem& font = mFontCache[fontId-1];
+
+    metrics = font.mMetrics;
+
+    // Adjust the metrics if the fixed-size font should be down-scaled
+    if( font.mIsFixedSizeBitmap &&
+        ( maxFixedSize > 0 ) &&
+        ( font.mFixedHeightPixels > maxFixedSize ) )
+    {
+      float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
+
+      metrics.ascender           *= scaleFactor;
+      metrics.descender          *= scaleFactor;
+      metrics.height             *= scaleFactor;
+      metrics.underlinePosition  *= scaleFactor;
+      metrics.underlineThickness *= scaleFactor;
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
+  }
+}
+
+GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
+                                              Character charcode )
+{
+  GlyphIndex index( 0 );
+
+  if( fontId > 0 &&
+      fontId-1 < mFontCache.size() )
+  {
+    FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+
+    index = FT_Get_Char_Index( ftFace, charcode );
+  }
+
+  return index;
+}
+
+bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
+                                          uint32_t size,
+                                          bool horizontal,
+                                          int maxFixedSize )
+{
+  bool success( true );
+
+  for( unsigned int i=0; i<size; ++i )
+  {
+    FontId fontId = array[i].fontId;
+
+    if( fontId > 0 &&
+        fontId-1 < mFontCache.size() )
+    {
+      const CacheItem& font = mFontCache[fontId-1];
+
+      FT_Face ftFace = font.mFreeTypeFace;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+      // Check to see if we should be loading a Fixed Size bitmap?
+      if ( font.mIsFixedSizeBitmap )
+      {
+        int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
+        if ( FT_Err_Ok == error )
+        {
+          array[i].width = font.mFixedWidthPixels;
+          array[i].height = font.mFixedHeightPixels;
+          array[i].advance = font.mFixedWidthPixels;
+          array[i].xBearing = 0.0f;
+          array[i].yBearing = font.mFixedHeightPixels;
+
+          // Adjust the metrics if the fixed-size font should be down-scaled
+          if( ( maxFixedSize > 0 ) &&
+              ( font.mFixedHeightPixels > maxFixedSize ) )
+          {
+            float scaleFactor = static_cast<float>(maxFixedSize) / static_cast<float>(font.mFixedHeightPixels);
+
+            array[i].width    *= scaleFactor;
+            array[i].height   *= scaleFactor;
+            array[i].advance  *= scaleFactor;
+            array[i].xBearing *= scaleFactor;
+            array[i].yBearing *= scaleFactor;
+
+            array[i].scaleFactor = scaleFactor;
+          }
+        }
+        else
+        {
+          DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
+          success = false;
+        }
+      }
+      else
+#endif
+      {
+        int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
+
+        if( FT_Err_Ok == error )
+        {
+          array[i].width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+          array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
+          if( horizontal )
+          {
+            array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
+            array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
+          }
+          else
+          {
+            array[i].xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
+            array[i].yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
+          }
+        }
+        else
+        {
+          success = false;
+        }
+      }
+    }
+    else
+    {
+      success = false;
+    }
+  }
+
+  return success;
+}
+
+BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
+                                              GlyphIndex glyphIndex )
+{
+  BufferImage bitmap;
+
+  if( fontId > 0 &&
+      fontId-1 < mFontCache.size() )
+  {
+    FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+
+    FT_Error error;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+    // Check to see if this is fixed size bitmap
+    if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
+    {
+      error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+    }
+    else
+#endif
+    {
+      error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
+    }
+    if( FT_Err_Ok == error )
+    {
+      FT_Glyph glyph;
+      error = FT_Get_Glyph( ftFace->glyph, &glyph );
+
+      // Convert to bitmap if necessary
+      if ( FT_Err_Ok == error )
+      {
+        if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
+        {
+          error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
+          if ( FT_Err_Ok == error )
+          {
+            FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
+            ConvertBitmap( bitmap, bitmapGlyph->bitmap );
+          }
+          else
+          {
+            DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
+          }
+        }
+        else
+        {
+          ConvertBitmap( bitmap, ftFace->glyph->bitmap );
+        }
+
+        // Created FT_Glyph object must be released with FT_Done_Glyph
+        FT_Done_Glyph( glyph );
+      }
+    }
+    else
+    {
+      DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
+    }
+  }
+
+  return bitmap;
+}
+
+const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 pointSize )
+{
+  // First look into the cache if there is an ellipsis glyph for the requested point size.
+  for( Vector<EllipsisItem>::ConstIterator it = mEllipsisCache.Begin(),
+         endIt = mEllipsisCache.End();
+       it != endIt;
+       ++it )
+  {
+    const EllipsisItem& item = *it;
+
+    if( fabsf( item.size - pointSize ) < Math::MACHINE_EPSILON_1000 )
+    {
+      // Use the glyph in the cache.
+      return item.glyph;
+    }
+  }
+
+  // No glyph has been found. Create one.
+  mEllipsisCache.PushBack( EllipsisItem() );
+  EllipsisItem& item = *( mEllipsisCache.End() - 1u );
+
+  item.size = pointSize;
+
+  // Find a font for the ellipsis glyph.
+  item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
+                                       pointSize,
+                                       false );
+
+  // Set the character index to access the glyph inside the font.
+  item.glyph.index = FT_Get_Char_Index( mFontCache[item.glyph.fontId-1].mFreeTypeFace,
+                                        ELLIPSIS_CHARACTER );
+
+  GetGlyphMetrics( &item.glyph, 1u, true, 0 );
+
+  return item.glyph;
+}
+
+void FontClient::Plugin::InitSystemFonts()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts \n");
+
+  FcFontSet* fontSet = GetFcFontSet();
+
+  if( fontSet )
+  {
+    // Reserve some space to avoid reallocations.
+    mSystemFonts.reserve( fontSet->nfont );
+
+    for( int i = 0u; i < fontSet->nfont; ++i )
+    {
+      FcPattern* fontPattern = fontSet->fonts[i];
+
+      FontPath path;
+
+      // Skip fonts with no path
+      if( GetFcString( fontPattern, FC_FILE, path ) )
+      {
+        mSystemFonts.push_back( FontDescription() );
+        FontDescription& fontDescription = mSystemFonts.back();
+
+        fontDescription.path = path;
+
+        int width = 0;
+        int weight = 0;
+        int slant = 0;
+        GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
+        GetFcInt( fontPattern, FC_WIDTH, width );
+        GetFcInt( fontPattern, FC_WEIGHT, weight );
+        GetFcInt( fontPattern, FC_SLANT, slant );
+        fontDescription.width = IntToWidthType( width );
+        fontDescription.weight = IntToWeightType( weight );
+        fontDescription.slant = IntToSlantType( slant );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::InitSystemFonts font family(%s)\n", fontDescription.family.c_str() );
+
+      }
+    }
+
+    FcFontSetDestroy( fontSet );
+  }
+}
+
+bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription )
+{
+  FcResult result = FcResultMatch;
+  FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
+
+  bool ret = false;
+
+  if( match )
+  {
+    int width = 0;
+    int weight = 0;
+    int slant = 0;
+    GetFcString( match, FC_FILE, fontDescription.path );
+    GetFcString( match, FC_FAMILY, fontDescription.family );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::MatchFontDescriptionToPattern matched:%s \n", fontDescription.family.c_str());
+    GetFcInt( match, FC_WIDTH, width );
+    GetFcInt( match, FC_WEIGHT, weight );
+    GetFcInt( match, FC_SLANT, slant );
+    fontDescription.width = IntToWidthType( width );
+    fontDescription.weight = IntToWeightType( weight );
+    fontDescription.slant = IntToSlantType( slant );
+    // destroyed the matched pattern
+    FcPatternDestroy( match );
+    ret = true;
+  }
+  return ret;
+}
+
+
+FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription )
+{
+  // create the cached font family lookup pattern
+  // a pattern holds a set of names, each name refers to a property of the font
+  FcPattern* fontFamilyPattern = FcPatternCreate();
+
+  // add a property to the pattern for the font family
+  FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
+
+  FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, FONT_WIDTH_TYPE_TO_INT[fontDescription.width] );
+  FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight] );
+  FcPatternAddInteger( fontFamilyPattern, FC_SLANT, FONT_SLANT_TYPE_TO_INT[fontDescription.slant] );
+
+  // Add a property of the pattern, to say we want to match TrueType fonts
+  FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
+
+  // modify the config, with the mFontFamilyPatterm
+  FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
+
+  // provide default values for unspecified properties in the font pattern
+  // e.g. patterns without a specified style or weight are set to Medium
+  FcDefaultSubstitute( fontFamilyPattern );
+
+  return fontFamilyPattern;
+}
+
+_FcFontSet* FontClient::Plugin::GetFcFontSet() const
+{
+  // create a new pattern.
+  // a pattern holds a set of names, each name refers to a property of the font
+  FcPattern* pattern = FcPatternCreate();
+
+  // create an object set used to define which properties are to be returned in the patterns from FcFontList.
+  FcObjectSet* objectSet = FcObjectSetCreate();
+
+  // build an object set from a list of property names
+  FcObjectSetAdd( objectSet, FC_FILE );
+  FcObjectSetAdd( objectSet, FC_FAMILY );
+  FcObjectSetAdd( objectSet, FC_WIDTH );
+  FcObjectSetAdd( objectSet, FC_WEIGHT );
+  FcObjectSetAdd( objectSet, FC_SLANT );
+
+  // get a list of fonts
+  // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
+  FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
+
+  // clear up the object set
+  if( objectSet )
+  {
+    FcObjectSetDestroy( objectSet );
+  }
+  // clear up the pattern
+  if( pattern )
+  {
+    FcPatternDestroy( pattern );
+  }
+
+  return fontset;
+}
+
+bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
+                                      const char* const n,
+                                      std::string& string )
+{
+  FcChar8* file = NULL;
+  const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
+
+  if( FcResultMatch == retVal )
+  {
+    // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
+    string.assign( reinterpret_cast<const char*>( file ) );
+
+    return true;
+  }
+
+  return false;
+}
+
+bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
+{
+  const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
+
+  if( FcResultMatch == retVal )
+  {
+    return true;
+  }
+
+  return false;
+}
+
+FontId FontClient::Plugin::CreateFont( const FontPath& path,
+                                       PointSize26Dot6 pointSize,
+                                       FaceIndex faceIndex,
+                                       bool cacheDescription )
+{
+  FontId id( 0 );
+
+  // Create & cache new font face
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+
+  if( FT_Err_Ok == error )
+  {
+    // Check to see if the font contains fixed sizes?
+    if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
+    {
+      // Ensure this size is available
+      for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+      {
+        if ( static_cast<FT_Pos>(pointSize) == ftFace->available_sizes[ i ].size )
+        {
+          // Tell Freetype to use this size
+          error = FT_Select_Size( ftFace, i );
+          if ( FT_Err_Ok != error )
+          {
+            DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
+          }
+          else
+          {
+            float fixedWidth  = static_cast< float >( ftFace->available_sizes[ i ].width );
+            float fixedHeight = static_cast< float >( ftFace->available_sizes[ i ].height );
+
+            // Indicate that the font is a fixed sized bitmap
+            FontMetrics metrics( fixedHeight, // The ascender in pixels.
+                                 0.0f,
+                                 fixedHeight, // The height in pixels.
+                                 0.0f,
+                                 0.0f );
+
+            mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, fixedWidth, fixedHeight ) );
+            id = mFontCache.size();
+
+            if( cacheDescription )
+            {
+              FontDescription description;
+              description.path = path;
+              description.family = FontFamily( ftFace->family_name );
+
+              // Note FreeType doesn't give too much info to build a proper font style.
+              if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
+              {
+                description.slant = FontSlant::ITALIC;
+              }
+              if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
+              {
+                description.weight = FontWeight::BOLD;
+              }
+
+              mFontDescriptionCache.push_back( description );
+            }
+            return id;
+          }
+        }
+      }
+
+      // Can't find this size
+      std::stringstream sizes;
+      for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+      {
+        if ( i )
+        {
+          sizes << ", ";
+        }
+        sizes << ftFace->available_sizes[ i ].size;
+      }
+      DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
+                       path.c_str(), pointSize, sizes.str().c_str() );
+    }
+    else
+    {
+      error = FT_Set_Char_Size( ftFace,
+                              0,
+                              pointSize,
+                              mDpiHorizontal,
+                              mDpiVertical );
+
+      if( FT_Err_Ok == error )
+      {
+
+        FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
+
+        FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
+                             static_cast< float >( ftMetrics.descender ) * FROM_266,
+                             static_cast< float >( ftMetrics.height    ) * FROM_266,
+                             static_cast< float >( ftFace->underline_position ) * FROM_266,
+                             static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
+
+        mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
+        id = mFontCache.size();
+
+        if( cacheDescription )
+        {
+          FontDescription description;
+          description.path = path;
+          description.family = FontFamily( ftFace->family_name );
+
+          // Note FreeType doesn't give too much info to build a proper font style.
+          if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
+          {
+            description.slant = FontSlant::ITALIC;
+          }
+          if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
+          {
+            description.weight = FontWeight::BOLD;
+          }
+
+          mFontDescriptionCache.push_back( description );
+        }
+      }
+      else
+      {
+        DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
+  }
+
+  return id;
+}
+
+void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
+                                        FT_Bitmap srcBitmap )
+{
+  if( srcBitmap.width*srcBitmap.rows > 0 )
+  {
+    switch( srcBitmap.pixel_mode )
+    {
+      case FT_PIXEL_MODE_GRAY:
+      {
+        if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
+        {
+          destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
+
+          PixelBuffer* destBuffer = destBitmap.GetBuffer();
+          if( destBuffer )
+          {
+            memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
+          }
+          else
+          {
+            DALI_LOG_ERROR( "GetBuffer returns null\n" );
+          }
+        }
+        break;
+      }
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+      case FT_PIXEL_MODE_BGRA:
+      {
+        if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
+        {
+          destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
+
+          PixelBuffer* destBuffer = destBitmap.GetBuffer();
+          if( destBuffer )
+          {
+            memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
+          }
+          else
+          {
+            DALI_LOG_ERROR( "GetBuffer returns null\n" );
+          }
+        }
+        break;
+      }
+#endif
+      default:
+      {
+        DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
+        break;
+      }
+    }
+  }
+}
+
+bool FontClient::Plugin::FindFont( const FontPath& path,
+                                   PointSize26Dot6 pointSize,
+                                   FaceIndex faceIndex,
+                                   FontId& fontId ) const
+{
+  fontId = 0u;
+  for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
+         endIt = mFontCache.end();
+       it != endIt;
+       ++it, ++fontId )
+  {
+    const CacheItem& cacheItem = *it;
+
+    if( cacheItem.mPointSize == pointSize &&
+        cacheItem.mFaceIndex == faceIndex &&
+        cacheItem.mPath == path )
+    {
+      ++fontId;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
+                                            FontDescriptionId& validatedFontId )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont fontDescription family(%s)\n", fontDescription.family.c_str() );
+
+  validatedFontId = 0u;
+
+  for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
+         endIt = mValidatedFontCache.end();
+       it != endIt;
+       ++it )
+  {
+    const FontDescriptionCacheItem& item = *it;
+
+    if( !fontDescription.family.empty() &&
+        ( fontDescription.family == item.fontDescription.family ) &&
+        ( fontDescription.width == item.fontDescription.width ) &&
+        ( fontDescription.weight == item.fontDescription.weight ) &&
+        ( fontDescription.slant == item.fontDescription.slant ) )
+    {
+      validatedFontId = item.index;
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont validated font family(%s) font id (%u) \n", fontDescription.family.c_str(), validatedFontId );
+
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindValidatedFont NOT VALIDATED return false\n" );
+
+  return false;
+}
+
+bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
+                                               FontList*& fontList )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList fontDescription family(%s)\n", fontDescription.family.c_str() );
+
+  fontList = NULL;
+
+  for( std::vector<FallbackCacheItem>::const_iterator it = mFallbackCache.begin(), endIt = mFallbackCache.end();
+       it != endIt;
+       ++it )
+  {
+    const FallbackCacheItem& item = *it;
+
+    if( !fontDescription.family.empty() &&
+        ( fontDescription.family == item.fontDescription.family ) &&
+        ( fontDescription.width == item.fontDescription.width ) &&
+        ( fontDescription.weight == item.fontDescription.weight ) &&
+        ( fontDescription.slant == item.fontDescription.slant ) )
+    {
+      fontList = item.fallbackFonts;
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList font family(%s) font-list (%p) \n", fontDescription.family.c_str(), fontList );
+
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::FindFallbackFontList NOT FOUND return false\n" );
+
+  return false;
+}
+
+bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
+                                   PointSize26Dot6 pointSize,
+                                   FontId& fontId )
+{
+  fontId = 0u;
+
+  for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
+         endIt = mFontIdCache.end();
+       it != endIt;
+       ++it )
+  {
+    const FontIdCacheItem& item = *it;
+
+    if( ( validatedFontId == item.validatedFontId ) &&
+        ( pointSize == item.pointSize ) )
+    {
+      fontId = item.fontId;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FontClient::Plugin::IsScalable( const FontPath& path )
+{
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
+  }
+  return ( ftFace->num_fixed_sizes == 0 );
+}
+
+bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
+{
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
+
+  FcResult result = FcResultMatch;
+
+  // match the pattern
+  FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+  bool isScalable = true;
+
+  if( match )
+  {
+    // Get the path to the font file name.
+    FontPath path;
+    GetFcString( match, FC_FILE, path );
+    isScalable = IsScalable( path );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
+                    fontDescription.family.c_str(),
+                    fontDescription.width,
+                    fontDescription.weight,
+                    fontDescription.slant );
+  }
+  FcPatternDestroy( fontFamilyPattern );
+  FcPatternDestroy( match );
+  return isScalable;
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
+{
+  // Empty the caller container
+  sizes.Clear();
+
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
+  }
+
+  // Fetch the number of fixed sizes available
+  if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
+  {
+    for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+    {
+      sizes.PushBack( ftFace->available_sizes[ i ].size );
+    }
+  }
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
+                                        Vector< PointSize26Dot6 >& sizes )
+{
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
+
+  FcResult result = FcResultMatch;
+
+  // match the pattern
+  FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+
+  if( match )
+  {
+    // Get the path to the font file name.
+    FontPath path;
+    GetFcString( match, FC_FILE, path );
+    GetFixedSizes( path, sizes );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "FreeType Cannot check font: %s %d %d %d\n",
+                    fontDescription.family.c_str(),
+                    fontDescription.width,
+                    fontDescription.weight,
+                    fontDescription.slant );
+  }
+  FcPatternDestroy( match );
+  FcPatternDestroy( fontFamilyPattern );
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/font-client-plugin-impl.h b/text/dali/internal/text-abstraction/font-client-plugin-impl.h
new file mode 100644 (file)
index 0000000..1d4dfc0
--- /dev/null
@@ -0,0 +1,432 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+// forward declarations of font config types.
+struct _FcFontSet;
+struct _FcPattern;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ *@brief Type used for indices addressing the vector with front descriptions of validated fonts.
+ */
+typedef uint32_t FontDescriptionId;
+
+/**
+ * @brief FontClient implementation.
+ */
+struct FontClient::Plugin
+{
+  /**
+   * @brief Caches an list of fallback fonts for a given font-description
+   */
+  struct FallbackCacheItem
+  {
+    FallbackCacheItem( const FontDescription& fontDescription, FontList* fallbackFonts );
+
+    FontDescription fontDescription; ///< The font description.
+    FontList* fallbackFonts;         ///< The list of fallback fonts for the given font-description.
+  };
+
+  /**
+   * @brief Caches an index to the vector of font descriptions for a given font.
+   */
+  struct FontDescriptionCacheItem
+  {
+    FontDescriptionCacheItem( const FontDescription& fontDescription,
+                              FontDescriptionId index );
+
+    FontDescription fontDescription; ///< The font description.
+    FontDescriptionId index;         ///< Index to the vector of font descriptions.
+  };
+
+  /**
+   * @brief Caches the font id of the pair font point size and the index to the vector of font descriptions of validated fonts.
+   */
+  struct FontIdCacheItem
+  {
+    FontIdCacheItem( FontDescriptionId validatedFontId,
+                     PointSize26Dot6 pointSize,
+                     FontId fontId );
+
+    FontDescriptionId validatedFontId; ///< Index to the vector with font descriptions.
+    PointSize26Dot6   pointSize;       ///< The font point size.
+    FontId            fontId;          ///< The font id.
+  };
+
+  /**
+   * @brief Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+   */
+  struct CacheItem
+  {
+    CacheItem( FT_Face ftFace,
+               const FontPath& path,
+               PointSize26Dot6 pointSize,
+               FaceIndex face,
+               const FontMetrics& metrics );
+
+    CacheItem( FT_Face ftFace,
+               const FontPath& path,
+               PointSize26Dot6 pointSize,
+               FaceIndex face,
+               const FontMetrics& metrics,
+               float fixedWidth,
+               float fixedHeight );
+
+    FT_Face mFreeTypeFace;       ///< The FreeType face.
+    FontPath mPath;              ///< The path to the font file name.
+    PointSize26Dot6 mPointSize;  ///< The font point size.
+    FaceIndex mFaceIndex;        ///< The face index.
+    FontMetrics mMetrics;        ///< The font metrics.
+    FT_Short mFixedWidthPixels;  ///< The height in pixels (fixed size bitmaps only)
+    FT_Short mFixedHeightPixels; ///< The height in pixels (fixed size bitmaps only)
+    bool mIsFixedSizeBitmap;     ///< Whether the font has fixed size bitmaps.
+  };
+
+  struct EllipsisItem
+  {
+    PointSize26Dot6 size;
+    GlyphInfo glyph;
+  };
+
+  /**
+   * Constructor.
+   *
+   * Initializes the FreeType library.
+   * Initializes the dpi values.
+   *
+   * @param[in] horizontalDpi The horizontal dpi.
+   * @param[in] verticalDpi The vertical dpi.
+   */
+  Plugin( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * Default destructor.
+   *
+   * Frees any allocated resource.
+   */
+  ~Plugin();
+
+  /**
+   * @copydoc Dali::FontClient::SetDpi()
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @copydoc Dali::FontClient::SetDefaultFont()
+   */
+  void SetDefaultFont( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetDefaultPlatformFontDescription()
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetDefaultFonts()
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @copydoc Dali::FontClient::GetSystemFonts()
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @copydoc Dali::FontClient::GetDescription()
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription ) const;
+
+  /**
+   * @copydoc Dali::FontClient::GetPointSize()
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @copydoc Dali::FontClient::FindFontForCharacter()
+   */
+  FontId FindFontForCharacter( const FontList& fontList,
+                               Character charcode,
+                               PointSize26Dot6 requestedSize,
+                               bool preferColor );
+
+  /**
+   * @copydoc Dali::FontClient::FindDefaultFont()
+   */
+  FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor );
+
+  /**
+   * @copydoc Dali::FontClient::FindFallbackFont()
+   */
+  FontId FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 requestedSize, bool preferColor );
+
+  /**
+   * @see Dali::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+   *
+   * @param[in] cacheDescription Whether to cache the font description.
+   */
+  FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription = true );
+
+  /**
+   * @copydoc Dali::FontClient::GetFontId( const FontDescription& fontDescription, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontDescription& fontDescription,
+                    PointSize26Dot6 pointSize,
+                    FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::FontClient::IsScalable( const FontPath& path )
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @copydoc Dali::FontClient::IsScalable( const FontDescription& fontDescription )
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @copydoc Dali::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  /**
+   * @copydoc Dali::FontClient::GetFontMetrics()
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics, int maxFixedSize );
+
+  /**
+   * @copydoc Dali::FontClient::GetGlyphIndex()
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @copydoc Dali::FontClient::GetGlyphMetrics()
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int maxFixedSize );
+
+  /**
+   * @copydoc Dali::FontClient::CreateBitmap()
+   */
+  BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @copydoc Dali::FontClient::GetEllipsisGlyph()
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize );
+
+private:
+
+  /**
+   * Caches the fonts present in the platform.
+   *
+   * Calls GetFcFontSet() to retrieve the fonts.
+   */
+  void InitSystemFonts();
+
+  /**
+   * Gets the FontDescription which matches the given pattern
+   * @param[in] pattern pattern to match against
+   * @param[out] fontDescription the resultant fontDescription that matched
+   * @return true if match found
+   */
+  bool MatchFontDescriptionToPattern( _FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription );
+
+  /**
+   * @brief Creates a font family pattern used to match fonts.
+   *
+   * @param[in] fontDescription The font to cache.
+   *
+   * @return The pattern.
+   */
+  _FcPattern* CreateFontFamilyPattern( const FontDescription& fontDescription );
+
+  /**
+   * Retrieves the fonts present in the platform.
+   *
+   * @return A font fonfig data structure with the platform's fonts.
+   */
+  _FcFontSet* GetFcFontSet() const;
+
+  /**
+   * Retrieves a font config object's value from a pattern.
+   *
+   * @param[in] pattern The font config pattern.
+   * @param[in] n The object.
+   * @param[out] string The object's value.
+   *
+   * @return @e true if the operation is successful.
+   */
+  bool GetFcString( const _FcPattern* const pattern, const char* const n, std::string& string );
+
+  /**
+   * Retrieves a font config object's value from a pattern.
+   *
+   * @param[in] pattern The font config pattern.
+   * @param[in] n The object.
+   * @param[out] intVal The object's value.
+   *
+   * @return @e true if the operation is successful.
+   */
+  bool GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal );
+
+  /**
+   * @brief Creates a font.
+   *
+   * @param[in] path The path to the font file name.
+   * @param[in] pointSize The font point size.
+   * @param[in] faceIndex A face index.
+   * @param[in] cacheDescription Whether to cache the font description.
+   *
+   * @return The font id.
+   */
+  FontId CreateFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription );
+
+  /**
+   * @brief Creates a fixed size font
+   *
+   * @param[in] path The path to the font file name.
+   * @param[in] pointSize The font point size( must be an available size ).
+   * @param[in] faceIndex A face index.
+   * @param[in] cacheDescription Whether to cache the font description.
+   *
+   * @return The font id.
+   */
+  FontId CreateFixedSizeFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription );
+
+  /**
+   *
+   * @param[in] destBitmap
+   * @param[in] srcBitmap
+   */
+  void ConvertBitmap( BufferImage& destBitmap, FT_Bitmap srcBitmap );
+
+  /**
+   * @brief Finds in the cache if there is a triplet with the path to the font file name, the font point size and the face index.
+   * If there is one , if writes the font id in the param @p fontId.
+   *
+   * @param[in] path Path to the font file name.
+   * @param[in] pointSize The font point size.
+   * @param[in] faceIndex The face index.
+   * @param[out] fontId The font id.
+   *
+   * @return @e true if there triplet is found.
+   */
+  bool FindFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& fontId ) const;
+
+  /**
+   * @brief Finds in the cache a cluster 'font family, font width, font weight, font slant'
+   * If there is one, it writes the index to the vector with font descriptions in the param @p validatedFontId.
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] validatedFontId The index to the vector with font descriptions.
+   *
+   * @return @e true if the pair is found.
+   */
+  bool FindValidatedFont( const FontDescription& fontDescription,
+                          FontDescriptionId& validatedFontId );
+
+  /**
+   * @brief Finds a fallback font list from the cache for a given font-description
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] A valid pointer to a font list, or NULL if not found.
+   */
+  bool FindFallbackFontList( const FontDescription& fontDescription,
+                             FontList*& fontList );
+
+  /**
+   * @brief Finds in the cache a pair 'validated font id and font point size'.
+   * If there is one it writes the font id in the param @p fontId.
+   *
+   * @param[in] validatedFontId Index to the vector with font descriptions.
+   * @param[in] pointSize The font point size.
+   * @param[out] fontId The font id.
+   *
+   * @return @e true if the pair is found.
+   */
+  bool FindFont( FontDescriptionId validatedFontId,
+                 PointSize26Dot6 pointSize,
+                 FontId& fontId );
+
+  /**
+   * @brief Validate a font description.
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] validatedFontId Result of validation
+   */
+  void ValidateFont( const FontDescription& fontDescription,
+                     FontDescriptionId& validatedFontId );
+
+  /**
+   * Helper for SetDefaultFont etc.
+   *
+   * @param[in] fontDescription A font description.
+   * @param[out] fontList A list of the fonts which are a close match for fontDescription.
+   */
+  void SetFontList( const FontDescription& fontDescription, FontList& fontList );
+
+  FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+  unsigned int mDpiHorizontal; ///< Horizontal dpi.
+  unsigned int mDpiVertical;   ///< Vertical dpi.
+
+  FontList mSystemFonts;       ///< Cached system fonts.
+  FontList mDefaultFonts;      ///< Cached default fonts.
+
+  std::vector<FallbackCacheItem> mFallbackCache; ///< Cached fallback font lists.
+
+  std::vector<CacheItem>                mFontCache;            ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+  std::vector<FontDescriptionCacheItem> mValidatedFontCache;   ///< Caches indices to the vector of font descriptions for a given font.
+  FontList                              mFontDescriptionCache; ///< Caches font descriptions for the validated font.
+  std::vector<FontIdCacheItem>          mFontIdCache;          ///< Caches font ids for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
+
+  Vector<EllipsisItem> mEllipsisCache;      ///< Caches ellipsis glyphs for a particular point size.
+};
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
diff --git a/text/dali/internal/text-abstraction/segmentation-impl.cpp b/text/dali/internal/text-abstraction/segmentation-impl.cpp
new file mode 100644 (file)
index 0000000..a517a42
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include "segmentation-impl.h"
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+
+// EXTERNAL INCLUDES
+#include <linebreak.h>
+#include <wordbreak.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+struct Segmentation::Plugin
+{
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo )
+  {
+    set_linebreaks_utf32( text, numberOfCharacters, NULL, breakInfo );
+  }
+
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo )
+  {
+    set_wordbreaks_utf32( text, numberOfCharacters, NULL, breakInfo );
+  }
+};
+
+Segmentation::Segmentation()
+: mPlugin( NULL )
+{}
+
+Segmentation::~Segmentation()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::Segmentation Segmentation::Get()
+{
+  TextAbstraction::Segmentation segmentationHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::Segmentation ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      Segmentation* impl = dynamic_cast< Internal::Segmentation* >( handle.GetObjectPtr() );
+      segmentationHandle = TextAbstraction::Segmentation( impl );
+    }
+    else // create and register the object
+    {
+      segmentationHandle = TextAbstraction::Segmentation( new Segmentation );
+      service.Register( typeid( segmentationHandle ), segmentationHandle );
+    }
+  }
+
+  return segmentationHandle;
+}
+
+void Segmentation::GetLineBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          LineBreakInfo* breakInfo )
+{
+  CreatePlugin();
+
+  mPlugin->GetLineBreakPositions( text, numberOfCharacters, breakInfo );
+}
+
+void Segmentation::GetWordBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          WordBreakInfo* breakInfo )
+{
+  CreatePlugin();
+
+  mPlugin->GetWordBreakPositions( text, numberOfCharacters, breakInfo );
+}
+
+void Segmentation::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/segmentation-impl.h b/text/dali/internal/text-abstraction/segmentation-impl.h
new file mode 100644 (file)
index 0000000..3d4b4a7
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/segmentation.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the Segmentation
+ */
+
+class Segmentation : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  Segmentation();
+
+  /**
+   * Destructor
+   */
+  ~Segmentation();
+
+  /**
+   * @copydoc Dali::Segmentation::Get()
+   */
+  static TextAbstraction::Segmentation Get();
+
+  /**
+   * @copydoc Dali::Segmentation::GetLineBreakPositions()
+   */
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo );
+
+
+  /**
+   * @copydoc Dali::Segmentation::GetWordBreakPositions()
+   */
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  Segmentation( const Segmentation& );
+
+  // Undefined assignment constructor.
+  Segmentation& operator=( Segmentation& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class Segmentation
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::Segmentation& GetImplementation( TextAbstraction::Segmentation& segmentation )
+{
+  DALI_ASSERT_ALWAYS( segmentation && "segmentation handle is empty" );
+  BaseObject& handle = segmentation.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::Segmentation&>( handle );
+}
+
+inline static const TextAbstraction::Internal::Segmentation& GetImplementation( const TextAbstraction::Segmentation& segmentation )
+{
+  DALI_ASSERT_ALWAYS( segmentation && "segmentation handle is empty" );
+  const BaseObject& handle = segmentation.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::Segmentation&>( handle );
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H__
diff --git a/text/dali/internal/text-abstraction/shaping-impl.cpp b/text/dali/internal/text-abstraction/shaping-impl.cpp
new file mode 100644 (file)
index 0000000..44a8703
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include "shaping-impl.h"
+
+// INTERNAL INCLUDES
+#include <singleton-service-impl.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <harfbuzz/hb.h>
+#include <harfbuzz/hb-ft.h>
+
+#include <ft2build.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+const char*        DEFAULT_LANGUAGE = "en";
+const unsigned int DEFAULT_LANGUAGE_LENGTH = 2u;
+const float        FROM_266 = 1.0f / 64.0f;
+
+const hb_script_t SCRIPT_TO_HARFBUZZ[] =
+{
+  HB_SCRIPT_COMMON,
+
+  HB_SCRIPT_CYRILLIC,
+  HB_SCRIPT_GREEK,
+  HB_SCRIPT_LATIN,
+
+  HB_SCRIPT_ARABIC,
+  HB_SCRIPT_HEBREW,
+
+  HB_SCRIPT_ARMENIAN,
+  HB_SCRIPT_GEORGIAN,
+
+  HB_SCRIPT_HAN,
+  HB_SCRIPT_HANGUL,
+  HB_SCRIPT_HIRAGANA,
+  HB_SCRIPT_KATAKANA,
+  HB_SCRIPT_BOPOMOFO,
+
+  HB_SCRIPT_BENGALI,
+  HB_SCRIPT_MYANMAR,
+  HB_SCRIPT_DEVANAGARI,
+  HB_SCRIPT_GUJARATI,
+  HB_SCRIPT_GURMUKHI,
+  HB_SCRIPT_KANNADA,
+  HB_SCRIPT_MALAYALAM,
+  HB_SCRIPT_ORIYA,
+  HB_SCRIPT_SINHALA,
+  HB_SCRIPT_TAMIL,
+  HB_SCRIPT_TELUGU,
+
+  HB_SCRIPT_LAO,
+  HB_SCRIPT_THAI,
+  HB_SCRIPT_KHMER,
+
+  HB_SCRIPT_UNKNOWN, // EMOJI
+  HB_SCRIPT_UNKNOWN, // SYMBOLS1
+  HB_SCRIPT_UNKNOWN, // SYMBOLS2
+  HB_SCRIPT_UNKNOWN, // SYMBOLS3
+  HB_SCRIPT_UNKNOWN, // SYMBOLS4
+  HB_SCRIPT_UNKNOWN, // SYMBOLS5
+  HB_SCRIPT_UNKNOWN
+};
+
+struct Shaping::Plugin
+{
+  Plugin()
+  : mFreeTypeLibrary( NULL ),
+    mIndices(),
+    mAdvance(),
+    mCharacterMap(),
+    mFontId( 0u )
+  {
+  }
+
+  ~Plugin()
+  {
+    FT_Done_FreeType( mFreeTypeLibrary );
+  }
+
+  void Initialize()
+  {
+    int error = FT_Init_FreeType( &mFreeTypeLibrary );
+    if( FT_Err_Ok != error )
+    {
+      DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
+    }
+  }
+
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script )
+  {
+    // Clear previoursly shaped texts.
+    mIndices.Clear();
+    mAdvance.Clear();
+    mCharacterMap.Clear();
+    mOffset.Clear();
+    mFontId = fontId;
+
+    // Reserve some space to avoid reallocations.
+    const Length numberOfGlyphs = static_cast<Length>( 1.3f * static_cast<float>( numberOfCharacters ) );
+    mIndices.Reserve( numberOfGlyphs );
+    mAdvance.Reserve( numberOfGlyphs );
+    mCharacterMap.Reserve( numberOfGlyphs );
+    mOffset.Reserve( 2u * numberOfGlyphs );
+
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+
+    // Get the font's path file name from the font Id.
+    FontDescription fontDescription;
+    fontClient.GetDescription( fontId, fontDescription );
+
+    // Create a FreeType font's face.
+    FT_Face face;
+    FT_Error retVal = FT_New_Face( mFreeTypeLibrary, fontDescription.path.c_str(), 0u, &face );
+    if( FT_Err_Ok != retVal )
+    {
+      DALI_LOG_ERROR( "Failed to open face: %s\n", fontDescription.path.c_str() );
+      return 0u;
+    }
+
+    unsigned int horizontalDpi = 0u;
+    unsigned int verticalDpi = 0u;
+    fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+    FT_Set_Char_Size( face,
+                      0u,
+                      fontClient.GetPointSize( fontId ),
+                      horizontalDpi,
+                      verticalDpi );
+
+    /* Get our harfbuzz font struct */
+    hb_font_t* harfBuzzFont;
+    harfBuzzFont = hb_ft_font_create( face, NULL );
+
+    /* Create a buffer for harfbuzz to use */
+    hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
+
+    const bool rtlDirection = IsRightToLeftScript( script );
+    hb_buffer_set_direction( harfBuzzBuffer,
+                             rtlDirection ? HB_DIRECTION_RTL : HB_DIRECTION_LTR ); /* or LTR */
+
+    hb_buffer_set_script( harfBuzzBuffer,
+                          SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
+
+    hb_buffer_set_language( harfBuzzBuffer,
+                            hb_language_from_string( DEFAULT_LANGUAGE,
+                                                     DEFAULT_LANGUAGE_LENGTH ) );
+
+    /* Layout the text */
+    hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
+
+    hb_shape( harfBuzzFont, harfBuzzBuffer, NULL, 0u );
+
+    /* Get glyph data */
+    unsigned int glyphCount;
+    hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
+    hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
+    const GlyphIndex lastGlyphIndex = glyphCount - 1u;
+    for( GlyphIndex i = 0u; i < glyphCount; )
+    {
+      if( rtlDirection )
+      {
+        // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
+        // The glyphs are needed in the logical order to layout the text in lines.
+        // Do not change the order of the glyphs if they belong to the same cluster.
+        GlyphIndex rtlIndex = lastGlyphIndex - i;
+
+        unsigned int cluster = glyphInfo[rtlIndex].cluster;
+        unsigned int previousCluster = cluster;
+        Length numberOfGlyphsInCluster = 0u;
+
+        while( ( cluster == previousCluster ) )
+        {
+          ++numberOfGlyphsInCluster;
+          previousCluster = cluster;
+
+          if( rtlIndex > 0u )
+          {
+            --rtlIndex;
+
+            cluster = glyphInfo[rtlIndex].cluster;
+          }
+          else
+          {
+            break;
+          }
+        }
+
+        rtlIndex = lastGlyphIndex - ( i + ( numberOfGlyphsInCluster - 1u ) );
+
+        for( GlyphIndex j = 0u; j < numberOfGlyphsInCluster; ++j )
+        {
+          const GlyphIndex index = rtlIndex + j;
+
+          mIndices.PushBack( glyphInfo[index].codepoint );
+          mAdvance.PushBack( floor( glyphPositions[index].x_advance * FROM_266 ) );
+          mCharacterMap.PushBack( glyphInfo[index].cluster );
+          mOffset.PushBack( floor( glyphPositions[index].x_offset * FROM_266 ) );
+          mOffset.PushBack( floor( glyphPositions[index].y_offset * FROM_266 ) );
+        }
+
+        i += numberOfGlyphsInCluster;
+      }
+      else
+      {
+        mIndices.PushBack( glyphInfo[i].codepoint );
+        mAdvance.PushBack( floor( glyphPositions[i].x_advance * FROM_266 ) );
+        mCharacterMap.PushBack( glyphInfo[i].cluster );
+        mOffset.PushBack( floor( glyphPositions[i].x_offset * FROM_266 ) );
+        mOffset.PushBack( floor( glyphPositions[i].y_offset * FROM_266 ) );
+
+        ++i;
+      }
+    }
+
+    /* Cleanup */
+    hb_buffer_destroy( harfBuzzBuffer );
+    hb_font_destroy( harfBuzzFont );
+    FT_Done_Face( face );
+
+    return mIndices.Count();
+  }
+
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap )
+  {
+    Vector<CharacterIndex>::ConstIterator indicesIt = mIndices.Begin();
+    Vector<float>::ConstIterator advanceIt = mAdvance.Begin();
+    Vector<float>::ConstIterator offsetIt = mOffset.Begin();
+    Vector<CharacterIndex>::ConstIterator characterMapIt = mCharacterMap.Begin();
+
+    for( GlyphIndex index = 0u, size = mIndices.Count(); index < size; ++index )
+    {
+      GlyphInfo& glyph = *( glyphInfo + index );
+      CharacterIndex& glyphToCharacter = *( glyphToCharacterMap + index );
+
+      glyph.fontId = mFontId;
+      glyph.index = *( indicesIt + index );
+      glyph.advance = *( advanceIt + index );
+
+      const GlyphIndex offsetIndex = 2u * index;
+      glyph.xBearing = *( offsetIt + offsetIndex );
+      glyph.yBearing = *( offsetIt + offsetIndex + 1u );
+
+      glyphToCharacter = *( characterMapIt + index );
+    }
+  }
+
+  FT_Library             mFreeTypeLibrary;
+
+  Vector<CharacterIndex> mIndices;
+  Vector<float>          mAdvance;
+  Vector<float>          mOffset;
+  Vector<CharacterIndex> mCharacterMap;
+  FontId                 mFontId;
+};
+
+Shaping::Shaping()
+: mPlugin( NULL )
+{
+}
+
+Shaping::~Shaping()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::Shaping Shaping::Get()
+{
+  TextAbstraction::Shaping shapingHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::Shaping ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      Shaping* impl = dynamic_cast< Internal::Shaping* >( handle.GetObjectPtr() );
+      shapingHandle = TextAbstraction::Shaping( impl );
+    }
+    else // create and register the object
+    {
+      shapingHandle = TextAbstraction::Shaping( new Shaping );
+      service.Register( typeid( shapingHandle ), shapingHandle );
+    }
+  }
+
+  return shapingHandle;
+}
+
+Length Shaping::Shape( const Character* const text,
+                       Length numberOfCharacters,
+                       FontId fontId,
+                       Script script )
+{
+  CreatePlugin();
+
+  return mPlugin->Shape( text,
+                         numberOfCharacters,
+                         fontId,
+                         script );
+}
+
+void Shaping::GetGlyphs( GlyphInfo* glyphInfo,
+                         CharacterIndex* glyphToCharacterMap )
+{
+  CreatePlugin();
+
+  mPlugin->GetGlyphs( glyphInfo,
+                      glyphToCharacterMap );
+}
+
+void Shaping::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+    mPlugin->Initialize();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/text/dali/internal/text-abstraction/shaping-impl.h b/text/dali/internal/text-abstraction/shaping-impl.h
new file mode 100644 (file)
index 0000000..2944cc7
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the Shaping
+ */
+class Shaping : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  Shaping();
+
+  /**
+   * Destructor
+   */
+  ~Shaping();
+
+  /**
+   * @copydoc Dali::Shaping::Get()
+   */
+  static TextAbstraction::Shaping Get();
+
+  /**
+   * @copydoc Dali::Shaping::Shape()
+   */
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script );
+
+  /**
+   * @copydoc Dali::Shaping::GetGlyphs()
+   */
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  Shaping( const Shaping& );
+
+  // Undefined assignment constructor.
+  Shaping& operator=( Shaping& );
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class Shaping
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::Shaping& GetImplementation( TextAbstraction::Shaping& shaping )
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::Shaping&>( handle );
+}
+
+inline static const TextAbstraction::Internal::Shaping& GetImplementation( const TextAbstraction::Shaping& shaping )
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  const BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::Shaping&>( handle );
+}
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H__
diff --git a/text/file.list b/text/file.list
new file mode 100644 (file)
index 0000000..15131fd
--- /dev/null
@@ -0,0 +1,29 @@
+# Add local source files here
+
+text_abstraction_src_files = \
+   $(text_src_dir)/dali/devel-api/text-abstraction/bidirectional-support.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-client.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-list.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-metrics.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/glyph-info.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/script.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/segmentation.cpp \
+   $(text_src_dir)/dali/devel-api/text-abstraction/shaping.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/bidirectional-support-impl.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/font-client-helper.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/font-client-impl.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/font-client-plugin-impl.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/segmentation-impl.cpp \
+   $(text_src_dir)/dali/internal/text-abstraction/shaping-impl.cpp
+
+text_abstraction_header_files = \
+   $(text_src_dir)/dali/devel-api/text-abstraction/bidirectional-support.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-client.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-list.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/font-metrics.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/glyph-info.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/script.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/segmentation.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/shaping.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/text-abstraction.h \
+   $(text_src_dir)/dali/devel-api/text-abstraction/text-abstraction-definitions.h